Fix UIA Word movement tests (#11253)

## Summary of the Pull Request
Fixes the 24 failing generated tests. 20 of them were fixed by enforcing the following rule: when moving backwards by word...
- a degenerate range moves to the beginning of the word, then to the word behind it.
- a non-degenerate range outright moves to the word behind it.

The fix was simple: if we're a degenerate range, check if we're at the beginning of the word. If not, move there. Otherwise, move to the word before it. See UiaTextRangeBase.cpp changes for implementation details.

Along the way, several misauthored tests were found:
- 2 generated tests:
   - Cause: MS Word considers a line break a word delimiter. We don't use line-wrapping to distinguish two separate words.
- `MovementAtExclusiveEnd` backwards word movement tests:
   - `end` will always be `writeTarget` because...
      - [degenerate range case] both `start` and `end` are moved to the beginning of the word (`writeTarget`)
      - [non-degenerate range case] from the `UiaTextRangeBase` bugfix, we should be moving to the word behind it.
   - this misauthored test was explicitly found by fixing the bug first explained here.

## References
#10925 Word navigation testing
This commit is contained in:
Carlos Zamora 2021-09-22 10:50:34 -07:00 committed by GitHub
parent 168d28b036
commit 5deb332607
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 87 additions and 56 deletions

View File

@ -89,7 +89,9 @@ constexpr til::point segment1LmidHistory{ segment1, midHistory.y() };
constexpr til::point segment1LmidTop{ segment1, midTop.y() };
constexpr til::point segment1LmidTopP1L{ segment1, midTopP1L.y() };
constexpr til::point segment2LmidDocEnd{ segment2, midDocEnd.y() };
constexpr til::point segment2LmidDocEndM1L{ segment2, midDocEndM1L.y() };
constexpr til::point segment2LmidHistory{ segment2, midHistory.y() };
constexpr til::point segment2LmidHistoryM1L{ segment2, midHistoryM1L.y() };
constexpr til::point segment2LmidHistoryP1L{ segment2, midHistoryP1L.y() };
constexpr til::point segment2LmidTop{ segment2, midTop.y() };
constexpr til::point segment2LmidTopP1L{ segment2, midTopP1L.y() };
@ -102,9 +104,7 @@ constexpr til::point segment3LmidTop{ segment3, midTop.y() };
constexpr til::point segment3LmidTopP1L{ segment3, midTopP1L.y() };
constexpr til::point segment4LlastCharPosM1L{ segment4, lastCharPosM1L.y() };
constexpr til::point segment4LmidDocEnd{ segment4, midDocEnd.y() };
constexpr til::point segment4LmidDocEndM1L{ segment4, midDocEndM1L.y() };
constexpr til::point segment4LmidHistory{ segment4, midHistory.y() };
constexpr til::point segment4LmidHistoryM1L{ segment4, midHistoryM1L.y() };
constexpr til::point segment4LmidTop{ segment4, midTop.y() };
struct GeneratedMovementTestInput
{
@ -3319,7 +3319,7 @@ static constexpr std::array<GeneratedMovementTest, 340> s_movementTests{
-3,
origin,
origin },
true },
false },
GeneratedMovementTest{
L"Move degenerate range at position 2 -1 times by Word",
GeneratedMovementTestInput{
@ -3331,7 +3331,7 @@ static constexpr std::array<GeneratedMovementTest, 340> s_movementTests{
-1,
segment2LmidTop,
segment2LmidTop },
true },
false },
GeneratedMovementTest{
L"Move degenerate range at position 2 0 times by Word",
GeneratedMovementTestInput{
@ -3439,7 +3439,7 @@ static constexpr std::array<GeneratedMovementTest, 340> s_movementTests{
-5,
segment3LmidHistoryM1L,
segment3LmidHistoryM1L },
true },
false },
GeneratedMovementTest{
L"Move degenerate range at position 3 -1 times by Word",
GeneratedMovementTestInput{
@ -3451,7 +3451,7 @@ static constexpr std::array<GeneratedMovementTest, 340> s_movementTests{
-1,
segment2LmidHistory,
segment2LmidHistory },
true },
false },
GeneratedMovementTest{
L"Move degenerate range at position 3 0 times by Word",
GeneratedMovementTestInput{
@ -3497,9 +3497,9 @@ static constexpr std::array<GeneratedMovementTest, 340> s_movementTests{
midHistoryP1C },
GeneratedMovementTestExpected{
-5,
segment3LmidHistoryM1L,
segment4LmidHistoryM1L },
true },
segment2LmidHistoryM1L,
segment3LmidHistoryM1L },
false },
GeneratedMovementTest{
L"Move non-degenerate range at position 3 -1 times by Word",
GeneratedMovementTestInput{
@ -3559,7 +3559,7 @@ static constexpr std::array<GeneratedMovementTest, 340> s_movementTests{
-5,
segment3LmidDocEndM1L,
segment3LmidDocEndM1L },
true },
false },
GeneratedMovementTest{
L"Move degenerate range at position 4 -1 times by Word",
GeneratedMovementTestInput{
@ -3571,7 +3571,7 @@ static constexpr std::array<GeneratedMovementTest, 340> s_movementTests{
-1,
segment2LmidDocEnd,
segment2LmidDocEnd },
true },
false },
GeneratedMovementTest{
L"Move degenerate range at position 4 0 times by Word",
GeneratedMovementTestInput{
@ -3617,9 +3617,9 @@ static constexpr std::array<GeneratedMovementTest, 340> s_movementTests{
midDocEndP1C },
GeneratedMovementTestExpected{
-5,
segment3LmidDocEndM1L,
segment4LmidDocEndM1L },
true },
segment2LmidDocEndM1L,
segment3LmidDocEndM1L },
false },
GeneratedMovementTest{
L"Move non-degenerate range at position 4 -1 times by Word",
GeneratedMovementTestInput{
@ -3679,7 +3679,7 @@ static constexpr std::array<GeneratedMovementTest, 340> s_movementTests{
-5,
lastCharPosLeft,
lastCharPosLeft },
true },
false },
GeneratedMovementTest{
L"Move degenerate range at position 5 -1 times by Word",
GeneratedMovementTestInput{
@ -3691,7 +3691,7 @@ static constexpr std::array<GeneratedMovementTest, 340> s_movementTests{
-1,
segment4LmidDocEnd,
segment4LmidDocEnd },
true },
false },
GeneratedMovementTest{
L"Move degenerate range at position 5 0 times by Word",
GeneratedMovementTestInput{
@ -3799,7 +3799,7 @@ static constexpr std::array<GeneratedMovementTest, 340> s_movementTests{
-5,
midDocEndLeft,
midDocEndLeft },
true },
false },
GeneratedMovementTest{
L"Move degenerate range at position 6 -1 times by Word",
GeneratedMovementTestInput{
@ -3811,7 +3811,7 @@ static constexpr std::array<GeneratedMovementTest, 340> s_movementTests{
-1,
segment4LmidDocEnd,
segment4LmidDocEnd },
true },
false },
GeneratedMovementTest{
L"Move degenerate range at position 6 0 times by Word",
GeneratedMovementTestInput{
@ -3859,7 +3859,7 @@ static constexpr std::array<GeneratedMovementTest, 340> s_movementTests{
-5,
midDocEndLeft,
midDocEndLeft },
true },
false },
GeneratedMovementTest{
L"Move non-degenerate range at position 6 -1 times by Word",
GeneratedMovementTestInput{
@ -3871,7 +3871,7 @@ static constexpr std::array<GeneratedMovementTest, 340> s_movementTests{
-1,
segment4LmidDocEnd,
segment4LmidDocEnd },
true },
false },
GeneratedMovementTest{
L"Move non-degenerate range at position 6 0 times by Word",
GeneratedMovementTestInput{
@ -3919,7 +3919,7 @@ static constexpr std::array<GeneratedMovementTest, 340> s_movementTests{
-5,
midDocEndLeft,
midDocEndLeft },
true },
false },
GeneratedMovementTest{
L"Move degenerate range at position 7 -1 times by Word",
GeneratedMovementTestInput{
@ -3931,7 +3931,7 @@ static constexpr std::array<GeneratedMovementTest, 340> s_movementTests{
-1,
segment4LmidDocEnd,
segment4LmidDocEnd },
true },
false },
GeneratedMovementTest{
L"Move degenerate range at position 7 0 times by Word",
GeneratedMovementTestInput{
@ -3979,7 +3979,7 @@ static constexpr std::array<GeneratedMovementTest, 340> s_movementTests{
-5,
midDocEndLeft,
midDocEndLeft },
true },
false },
GeneratedMovementTest{
L"Move non-degenerate range at position 7 -1 times by Word",
GeneratedMovementTestInput{
@ -3991,7 +3991,7 @@ static constexpr std::array<GeneratedMovementTest, 340> s_movementTests{
-1,
segment4LmidDocEnd,
segment4LmidDocEnd },
true },
false },
GeneratedMovementTest{
L"Move non-degenerate range at position 7 0 times by Word",
GeneratedMovementTestInput{
@ -4039,7 +4039,7 @@ static constexpr std::array<GeneratedMovementTest, 340> s_movementTests{
-5,
midDocEndLeft,
midDocEndLeft },
true },
false },
GeneratedMovementTest{
L"Move degenerate range at position 8 -1 times by Word",
GeneratedMovementTestInput{
@ -4051,7 +4051,7 @@ static constexpr std::array<GeneratedMovementTest, 340> s_movementTests{
-1,
segment4LmidDocEnd,
segment4LmidDocEnd },
true },
false },
GeneratedMovementTest{
L"Move degenerate range at position 8 0 times by Word",
GeneratedMovementTestInput{
@ -4099,7 +4099,7 @@ static constexpr std::array<GeneratedMovementTest, 340> s_movementTests{
-5,
midDocEndLeft,
midDocEndLeft },
true },
false },
GeneratedMovementTest{
L"Move non-degenerate range at position 8 -1 times by Word",
GeneratedMovementTestInput{
@ -4111,7 +4111,7 @@ static constexpr std::array<GeneratedMovementTest, 340> s_movementTests{
-1,
segment4LmidDocEnd,
segment4LmidDocEnd },
true },
false },
GeneratedMovementTest{
L"Move non-degenerate range at position 8 0 times by Word",
GeneratedMovementTestInput{
@ -4159,7 +4159,7 @@ static constexpr std::array<GeneratedMovementTest, 340> s_movementTests{
-5,
midDocEndLeft,
midDocEndLeft },
true },
false },
GeneratedMovementTest{
L"Move degenerate range at position 9 -1 times by Word",
GeneratedMovementTestInput{
@ -4171,7 +4171,7 @@ static constexpr std::array<GeneratedMovementTest, 340> s_movementTests{
-1,
segment4LmidDocEnd,
segment4LmidDocEnd },
true },
false },
GeneratedMovementTest{
L"Move degenerate range at position 9 0 times by Word",
GeneratedMovementTestInput{

View File

@ -1417,11 +1417,13 @@ class UiaTextRangeTests
// reset the UTR
if (degenerate)
{
// UTR: (exclusive, exclusive) range
const auto utrStart{ atDocumentEnd ? documentEndExclusive : endExclusive };
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<UiaTextRange>(&utr, _pUiaData, &_dummyProvider, utrStart, utrEnd));
}
else
{
// UTR: (inclusive, exclusive) range
const auto utrStart{ atDocumentEnd ? documentEndInclusive : endInclusive };
THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize<UiaTextRange>(&utr, _pUiaData, &_dummyProvider, utrStart, utrEnd));
}
@ -1443,8 +1445,8 @@ class UiaTextRangeTests
else if (textUnit <= TextUnit::TextUnit_Word)
{
VERIFY_ARE_EQUAL(-1, moveAmt);
VERIFY_ARE_EQUAL(origin, til::point{ utr->_start });
VERIFY_ARE_EQUAL(degenerate || !atDocumentEnd ? origin : writeTarget, til::point{ utr->_end });
VERIFY_ARE_EQUAL(degenerate || !atDocumentEnd ? writeTarget : origin, til::point{ utr->_start });
VERIFY_ARE_EQUAL(writeTarget, til::point{ utr->_end });
}
else if (textUnit <= TextUnit::TextUnit_Line)
{

View File

@ -1522,6 +1522,14 @@ void UiaTextRangeBase::_moveEndpointByUnitWord(_In_ const int moveCount,
{
success = false;
}
else if (allowBottomExclusive && _tryMoveToWordStart(buffer, documentEnd, resultPos))
{
// IMPORTANT: _tryMoveToWordStart modifies resultPos if successful
// Degenerate ranges first move to the beginning of the word,
// but if we're already at the beginning of the word, we continue
// to the next branch and move to the previous word!
(*pAmountMoved)--;
}
else if (buffer.MoveToPreviousWord(nextPos, _wordDelimiters))
{
resultPos = nextPos;
@ -1541,6 +1549,26 @@ void UiaTextRangeBase::_moveEndpointByUnitWord(_In_ const int moveCount,
SetEndpoint(endpoint, resultPos);
}
// Routine Description:
// - tries to move resultingPos to the beginning of the word
// Arguments:
// - buffer - the text buffer we're operating on
// - documentEnd - the document end of the buffer (see _getDocumentEnd())
// - resultingPos - the position we're starting from and modifying
// Return Value:
// - true --> we were not at the beginning of the word, and we updated resultingPos to be so
// - false --> otherwise (we're already at the beginning of the word)
bool UiaTextRangeBase::_tryMoveToWordStart(const TextBuffer& buffer, const til::point documentEnd, COORD& resultingPos) const
{
const auto wordStart{ buffer.GetWordStart(resultingPos, _wordDelimiters, true, documentEnd) };
if (resultingPos != wordStart)
{
resultingPos = wordStart;
return true;
}
return false;
}
// Routine Description:
// - moves the UTR's endpoint by moveCount times by line.
// - if endpoints crossed, the degenerate range is created and both endpoints are moved

View File

@ -182,6 +182,7 @@ namespace Microsoft::Console::Types
std::optional<bool> _verifyAttr(TEXTATTRIBUTEID attributeId, VARIANT val, const TextAttribute& attr) const;
bool _initializeAttrQuery(TEXTATTRIBUTEID attributeId, VARIANT* pRetVal, const TextAttribute& attr) const;
bool _tryMoveToWordStart(const TextBuffer& buffer, const til::point documentEnd, COORD& resultingPos) const;
COORD _getInclusiveEnd() noexcept;

View File

@ -264,8 +264,8 @@ FALSE,1,TextUnit_Word,-1,origin,originP1C,0,origin,segment1LmidTop,FALSE
FALSE,1,TextUnit_Word,0,origin,originP1C,0,origin,segment1LmidTop,FALSE
FALSE,1,TextUnit_Word,1,origin,originP1C,1,segment1LmidTop,segment2LmidTop,FALSE
FALSE,1,TextUnit_Word,5,origin,originP1C,5,segment0LmidTopP1L,segment1LmidTopP1L,FALSE
TRUE,2,TextUnit_Word,-5,midTop,midTop,-3,origin,origin,TRUE
TRUE,2,TextUnit_Word,-1,midTop,midTop,-1,segment2LmidTop,segment2LmidTop,TRUE
TRUE,2,TextUnit_Word,-5,midTop,midTop,-3,origin,origin,FALSE
TRUE,2,TextUnit_Word,-1,midTop,midTop,-1,segment2LmidTop,segment2LmidTop,FALSE
TRUE,2,TextUnit_Word,0,midTop,midTop,0,midTop,midTop,FALSE
TRUE,2,TextUnit_Word,1,midTop,midTop,1,segment3LmidTop,segment3LmidTop,FALSE
TRUE,2,TextUnit_Word,5,midTop,midTop,5,segment2LmidTopP1L,segment2LmidTopP1L,FALSE
@ -274,28 +274,28 @@ FALSE,2,TextUnit_Word,-1,midTop,midTopP1C,-1,segment1LmidTop,segment2LmidTop,FAL
FALSE,2,TextUnit_Word,0,midTop,midTopP1C,0,segment2LmidTop,segment3LmidTop,FALSE
FALSE,2,TextUnit_Word,1,midTop,midTopP1C,1,segment3LmidTop,segment4LmidTop,FALSE
FALSE,2,TextUnit_Word,5,midTop,midTopP1C,5,segment2LmidTopP1L,segment3LmidTopP1L,FALSE
TRUE,3,TextUnit_Word,-5,midHistory,midHistory,-5,segment3LmidHistoryM1L,segment3LmidHistoryM1L,TRUE
TRUE,3,TextUnit_Word,-1,midHistory,midHistory,-1,segment2LmidHistory,segment2LmidHistory,TRUE
TRUE,3,TextUnit_Word,-5,midHistory,midHistory,-5,segment3LmidHistoryM1L,segment3LmidHistoryM1L,FALSE
TRUE,3,TextUnit_Word,-1,midHistory,midHistory,-1,segment2LmidHistory,segment2LmidHistory,FALSE
TRUE,3,TextUnit_Word,0,midHistory,midHistory,0,midHistory,midHistory,FALSE
TRUE,3,TextUnit_Word,1,midHistory,midHistory,1,segment3LmidHistory,segment3LmidHistory,FALSE
TRUE,3,TextUnit_Word,5,midHistory,midHistory,5,segment2LmidHistoryP1L,segment2LmidHistoryP1L,FALSE
FALSE,3,TextUnit_Word,-5,midHistory,midHistoryP1C,-5,segment3LmidHistoryM1L,segment4LmidHistoryM1L,TRUE
FALSE,3,TextUnit_Word,-5,midHistory,midHistoryP1C,-5,segment2LmidHistoryM1L,segment3LmidHistoryM1L,FALSE
FALSE,3,TextUnit_Word,-1,midHistory,midHistoryP1C,-1,segment1LmidHistory,segment2LmidHistory,FALSE
FALSE,3,TextUnit_Word,0,midHistory,midHistoryP1C,0,segment2LmidHistory,segment3LmidHistory,FALSE
FALSE,3,TextUnit_Word,1,midHistory,midHistoryP1C,1,segment3LmidHistory,segment4LmidHistory,FALSE
FALSE,3,TextUnit_Word,5,midHistory,midHistoryP1C,5,segment2LmidHistoryP1L,segment3LmidHistoryP1L,FALSE
TRUE,4,TextUnit_Word,-5,midDocEnd,midDocEnd,-5,segment3LmidDocEndM1L,segment3LmidDocEndM1L,TRUE
TRUE,4,TextUnit_Word,-1,midDocEnd,midDocEnd,-1,segment2LmidDocEnd,segment2LmidDocEnd,TRUE
TRUE,4,TextUnit_Word,-5,midDocEnd,midDocEnd,-5,segment3LmidDocEndM1L,segment3LmidDocEndM1L,FALSE
TRUE,4,TextUnit_Word,-1,midDocEnd,midDocEnd,-1,segment2LmidDocEnd,segment2LmidDocEnd,FALSE
TRUE,4,TextUnit_Word,0,midDocEnd,midDocEnd,0,midDocEnd,midDocEnd,FALSE
TRUE,4,TextUnit_Word,1,midDocEnd,midDocEnd,1,segment3LmidDocEnd,segment3LmidDocEnd,FALSE
TRUE,4,TextUnit_Word,5,midDocEnd,midDocEnd,3,docEnd,docEnd,FALSE
FALSE,4,TextUnit_Word,-5,midDocEnd,midDocEndP1C,-5,segment3LmidDocEndM1L,segment4LmidDocEndM1L,TRUE
FALSE,4,TextUnit_Word,-5,midDocEnd,midDocEndP1C,-5,segment2LmidDocEndM1L,segment3LmidDocEndM1L,FALSE
FALSE,4,TextUnit_Word,-1,midDocEnd,midDocEndP1C,-1,segment1LmidDocEnd,segment2LmidDocEnd,FALSE
FALSE,4,TextUnit_Word,0,midDocEnd,midDocEndP1C,0,segment2LmidDocEnd,segment3LmidDocEnd,FALSE
FALSE,4,TextUnit_Word,1,midDocEnd,midDocEndP1C,1,segment3LmidDocEnd,segment4LmidDocEnd,FALSE
FALSE,4,TextUnit_Word,5,midDocEnd,midDocEndP1C,2,segment4LmidDocEnd,docEnd,FALSE
TRUE,5,TextUnit_Word,-5,lastCharPos,lastCharPos,-5,lastCharPosLeft,lastCharPosLeft,TRUE
TRUE,5,TextUnit_Word,-1,lastCharPos,lastCharPos,-1,segment4LmidDocEnd,segment4LmidDocEnd,TRUE
TRUE,5,TextUnit_Word,-5,lastCharPos,lastCharPos,-5,lastCharPosLeft,lastCharPosLeft,FALSE
TRUE,5,TextUnit_Word,-1,lastCharPos,lastCharPos,-1,segment4LmidDocEnd,segment4LmidDocEnd,FALSE
TRUE,5,TextUnit_Word,0,lastCharPos,lastCharPos,0,lastCharPos,lastCharPos,FALSE
TRUE,5,TextUnit_Word,1,lastCharPos,lastCharPos,1,docEnd,docEnd,FALSE
TRUE,5,TextUnit_Word,5,lastCharPos,lastCharPos,1,docEnd,docEnd,FALSE
@ -304,38 +304,38 @@ FALSE,5,TextUnit_Word,-1,lastCharPos,lastCharPosP1C,-1,segment3LmidDocEnd,segmen
FALSE,5,TextUnit_Word,0,lastCharPos,lastCharPosP1C,0,segment4LmidDocEnd,docEnd,FALSE
FALSE,5,TextUnit_Word,1,lastCharPos,lastCharPosP1C,0,segment4LmidDocEnd,docEnd,FALSE
FALSE,5,TextUnit_Word,5,lastCharPos,lastCharPosP1C,0,segment4LmidDocEnd,docEnd,FALSE
TRUE,6,TextUnit_Word,-5,docEnd,docEnd,-5,midDocEndLeft,midDocEndLeft,TRUE
TRUE,6,TextUnit_Word,-1,docEnd,docEnd,-1,segment4LmidDocEnd,segment4LmidDocEnd,TRUE
TRUE,6,TextUnit_Word,-5,docEnd,docEnd,-5,midDocEndLeft,midDocEndLeft,FALSE
TRUE,6,TextUnit_Word,-1,docEnd,docEnd,-1,segment4LmidDocEnd,segment4LmidDocEnd,FALSE
TRUE,6,TextUnit_Word,0,docEnd,docEnd,0,docEnd,docEnd,FALSE
TRUE,6,TextUnit_Word,1,docEnd,docEnd,0,docEnd,docEnd,FALSE
TRUE,6,TextUnit_Word,5,docEnd,docEnd,0,docEnd,docEnd,FALSE
FALSE,6,TextUnit_Word,-5,docEnd,docEndP1C,-5,midDocEndLeft,midDocEndLeft,TRUE
FALSE,6,TextUnit_Word,-1,docEnd,docEndP1C,-1,segment4LmidDocEnd,segment4LmidDocEnd,TRUE
FALSE,6,TextUnit_Word,-5,docEnd,docEndP1C,-5,midDocEndLeft,midDocEndLeft,FALSE
FALSE,6,TextUnit_Word,-1,docEnd,docEndP1C,-1,segment4LmidDocEnd,segment4LmidDocEnd,FALSE
FALSE,6,TextUnit_Word,0,docEnd,docEndP1C,0,docEnd,docEnd,FALSE
FALSE,6,TextUnit_Word,1,docEnd,docEndP1C,0,docEnd,docEnd,FALSE
FALSE,6,TextUnit_Word,5,docEnd,docEndP1C,0,docEnd,docEnd,FALSE
TRUE,7,TextUnit_Word,-5,midEmptySpace,midEmptySpace,-5,midDocEndLeft,midDocEndLeft,TRUE
TRUE,7,TextUnit_Word,-1,midEmptySpace,midEmptySpace,-1,segment4LmidDocEnd,segment4LmidDocEnd,TRUE
TRUE,7,TextUnit_Word,-5,midEmptySpace,midEmptySpace,-5,midDocEndLeft,midDocEndLeft,FALSE
TRUE,7,TextUnit_Word,-1,midEmptySpace,midEmptySpace,-1,segment4LmidDocEnd,segment4LmidDocEnd,FALSE
TRUE,7,TextUnit_Word,0,midEmptySpace,midEmptySpace,0,docEnd,docEnd,FALSE
TRUE,7,TextUnit_Word,1,midEmptySpace,midEmptySpace,0,docEnd,docEnd,FALSE
TRUE,7,TextUnit_Word,5,midEmptySpace,midEmptySpace,0,docEnd,docEnd,FALSE
FALSE,7,TextUnit_Word,-5,midEmptySpace,midEmptySpaceP1C,-5,midDocEndLeft,midDocEndLeft,TRUE
FALSE,7,TextUnit_Word,-1,midEmptySpace,midEmptySpaceP1C,-1,segment4LmidDocEnd,segment4LmidDocEnd,TRUE
FALSE,7,TextUnit_Word,-5,midEmptySpace,midEmptySpaceP1C,-5,midDocEndLeft,midDocEndLeft,FALSE
FALSE,7,TextUnit_Word,-1,midEmptySpace,midEmptySpaceP1C,-1,segment4LmidDocEnd,segment4LmidDocEnd,FALSE
FALSE,7,TextUnit_Word,0,midEmptySpace,midEmptySpaceP1C,0,docEnd,docEnd,FALSE
FALSE,7,TextUnit_Word,1,midEmptySpace,midEmptySpaceP1C,0,docEnd,docEnd,FALSE
FALSE,7,TextUnit_Word,5,midEmptySpace,midEmptySpaceP1C,0,docEnd,docEnd,FALSE
TRUE,8,TextUnit_Word,-5,bufferEnd,bufferEnd,-5,midDocEndLeft,midDocEndLeft,TRUE
TRUE,8,TextUnit_Word,-1,bufferEnd,bufferEnd,-1,segment4LmidDocEnd,segment4LmidDocEnd,TRUE
TRUE,8,TextUnit_Word,-5,bufferEnd,bufferEnd,-5,midDocEndLeft,midDocEndLeft,FALSE
TRUE,8,TextUnit_Word,-1,bufferEnd,bufferEnd,-1,segment4LmidDocEnd,segment4LmidDocEnd,FALSE
TRUE,8,TextUnit_Word,0,bufferEnd,bufferEnd,0,docEnd,docEnd,FALSE
TRUE,8,TextUnit_Word,1,bufferEnd,bufferEnd,0,docEnd,docEnd,FALSE
TRUE,8,TextUnit_Word,5,bufferEnd,bufferEnd,0,docEnd,docEnd,FALSE
FALSE,8,TextUnit_Word,-5,bufferEnd,endExclusive,-5,midDocEndLeft,midDocEndLeft,TRUE
FALSE,8,TextUnit_Word,-1,bufferEnd,endExclusive,-1,segment4LmidDocEnd,segment4LmidDocEnd,TRUE
FALSE,8,TextUnit_Word,-5,bufferEnd,endExclusive,-5,midDocEndLeft,midDocEndLeft,FALSE
FALSE,8,TextUnit_Word,-1,bufferEnd,endExclusive,-1,segment4LmidDocEnd,segment4LmidDocEnd,FALSE
FALSE,8,TextUnit_Word,0,bufferEnd,endExclusive,0,docEnd,docEnd,FALSE
FALSE,8,TextUnit_Word,1,bufferEnd,endExclusive,0,docEnd,docEnd,FALSE
FALSE,8,TextUnit_Word,5,bufferEnd,endExclusive,0,docEnd,docEnd,FALSE
TRUE,9,TextUnit_Word,-5,endExclusive,endExclusive,-5,midDocEndLeft,midDocEndLeft,TRUE
TRUE,9,TextUnit_Word,-1,endExclusive,endExclusive,-1,segment4LmidDocEnd,segment4LmidDocEnd,TRUE
TRUE,9,TextUnit_Word,-5,endExclusive,endExclusive,-5,midDocEndLeft,midDocEndLeft,FALSE
TRUE,9,TextUnit_Word,-1,endExclusive,endExclusive,-1,segment4LmidDocEnd,segment4LmidDocEnd,FALSE
TRUE,9,TextUnit_Word,0,endExclusive,endExclusive,0,docEnd,docEnd,FALSE
TRUE,9,TextUnit_Word,1,endExclusive,endExclusive,0,docEnd,docEnd,FALSE
TRUE,9,TextUnit_Word,5,endExclusive,endExclusive,0,docEnd,docEnd,FALSE

1 Degenerate Position TextUnit MoveAmount Start End Result_MoveAmount Result_Start Result_End Skip
264 FALSE 1 TextUnit_Word 0 origin originP1C 0 origin segment1LmidTop FALSE
265 FALSE 1 TextUnit_Word 1 origin originP1C 1 segment1LmidTop segment2LmidTop FALSE
266 FALSE 1 TextUnit_Word 5 origin originP1C 5 segment0LmidTopP1L segment1LmidTopP1L FALSE
267 TRUE 2 TextUnit_Word -5 midTop midTop -3 origin origin TRUE FALSE
268 TRUE 2 TextUnit_Word -1 midTop midTop -1 segment2LmidTop segment2LmidTop TRUE FALSE
269 TRUE 2 TextUnit_Word 0 midTop midTop 0 midTop midTop FALSE
270 TRUE 2 TextUnit_Word 1 midTop midTop 1 segment3LmidTop segment3LmidTop FALSE
271 TRUE 2 TextUnit_Word 5 midTop midTop 5 segment2LmidTopP1L segment2LmidTopP1L FALSE
274 FALSE 2 TextUnit_Word 0 midTop midTopP1C 0 segment2LmidTop segment3LmidTop FALSE
275 FALSE 2 TextUnit_Word 1 midTop midTopP1C 1 segment3LmidTop segment4LmidTop FALSE
276 FALSE 2 TextUnit_Word 5 midTop midTopP1C 5 segment2LmidTopP1L segment3LmidTopP1L FALSE
277 TRUE 3 TextUnit_Word -5 midHistory midHistory -5 segment3LmidHistoryM1L segment3LmidHistoryM1L TRUE FALSE
278 TRUE 3 TextUnit_Word -1 midHistory midHistory -1 segment2LmidHistory segment2LmidHistory TRUE FALSE
279 TRUE 3 TextUnit_Word 0 midHistory midHistory 0 midHistory midHistory FALSE
280 TRUE 3 TextUnit_Word 1 midHistory midHistory 1 segment3LmidHistory segment3LmidHistory FALSE
281 TRUE 3 TextUnit_Word 5 midHistory midHistory 5 segment2LmidHistoryP1L segment2LmidHistoryP1L FALSE
282 FALSE 3 TextUnit_Word -5 midHistory midHistoryP1C -5 segment3LmidHistoryM1L segment2LmidHistoryM1L segment4LmidHistoryM1L segment3LmidHistoryM1L TRUE FALSE
283 FALSE 3 TextUnit_Word -1 midHistory midHistoryP1C -1 segment1LmidHistory segment2LmidHistory FALSE
284 FALSE 3 TextUnit_Word 0 midHistory midHistoryP1C 0 segment2LmidHistory segment3LmidHistory FALSE
285 FALSE 3 TextUnit_Word 1 midHistory midHistoryP1C 1 segment3LmidHistory segment4LmidHistory FALSE
286 FALSE 3 TextUnit_Word 5 midHistory midHistoryP1C 5 segment2LmidHistoryP1L segment3LmidHistoryP1L FALSE
287 TRUE 4 TextUnit_Word -5 midDocEnd midDocEnd -5 segment3LmidDocEndM1L segment3LmidDocEndM1L TRUE FALSE
288 TRUE 4 TextUnit_Word -1 midDocEnd midDocEnd -1 segment2LmidDocEnd segment2LmidDocEnd TRUE FALSE
289 TRUE 4 TextUnit_Word 0 midDocEnd midDocEnd 0 midDocEnd midDocEnd FALSE
290 TRUE 4 TextUnit_Word 1 midDocEnd midDocEnd 1 segment3LmidDocEnd segment3LmidDocEnd FALSE
291 TRUE 4 TextUnit_Word 5 midDocEnd midDocEnd 3 docEnd docEnd FALSE
292 FALSE 4 TextUnit_Word -5 midDocEnd midDocEndP1C -5 segment3LmidDocEndM1L segment2LmidDocEndM1L segment4LmidDocEndM1L segment3LmidDocEndM1L TRUE FALSE
293 FALSE 4 TextUnit_Word -1 midDocEnd midDocEndP1C -1 segment1LmidDocEnd segment2LmidDocEnd FALSE
294 FALSE 4 TextUnit_Word 0 midDocEnd midDocEndP1C 0 segment2LmidDocEnd segment3LmidDocEnd FALSE
295 FALSE 4 TextUnit_Word 1 midDocEnd midDocEndP1C 1 segment3LmidDocEnd segment4LmidDocEnd FALSE
296 FALSE 4 TextUnit_Word 5 midDocEnd midDocEndP1C 2 segment4LmidDocEnd docEnd FALSE
297 TRUE 5 TextUnit_Word -5 lastCharPos lastCharPos -5 lastCharPosLeft lastCharPosLeft TRUE FALSE
298 TRUE 5 TextUnit_Word -1 lastCharPos lastCharPos -1 segment4LmidDocEnd segment4LmidDocEnd TRUE FALSE
299 TRUE 5 TextUnit_Word 0 lastCharPos lastCharPos 0 lastCharPos lastCharPos FALSE
300 TRUE 5 TextUnit_Word 1 lastCharPos lastCharPos 1 docEnd docEnd FALSE
301 TRUE 5 TextUnit_Word 5 lastCharPos lastCharPos 1 docEnd docEnd FALSE
304 FALSE 5 TextUnit_Word 0 lastCharPos lastCharPosP1C 0 segment4LmidDocEnd docEnd FALSE
305 FALSE 5 TextUnit_Word 1 lastCharPos lastCharPosP1C 0 segment4LmidDocEnd docEnd FALSE
306 FALSE 5 TextUnit_Word 5 lastCharPos lastCharPosP1C 0 segment4LmidDocEnd docEnd FALSE
307 TRUE 6 TextUnit_Word -5 docEnd docEnd -5 midDocEndLeft midDocEndLeft TRUE FALSE
308 TRUE 6 TextUnit_Word -1 docEnd docEnd -1 segment4LmidDocEnd segment4LmidDocEnd TRUE FALSE
309 TRUE 6 TextUnit_Word 0 docEnd docEnd 0 docEnd docEnd FALSE
310 TRUE 6 TextUnit_Word 1 docEnd docEnd 0 docEnd docEnd FALSE
311 TRUE 6 TextUnit_Word 5 docEnd docEnd 0 docEnd docEnd FALSE
312 FALSE 6 TextUnit_Word -5 docEnd docEndP1C -5 midDocEndLeft midDocEndLeft TRUE FALSE
313 FALSE 6 TextUnit_Word -1 docEnd docEndP1C -1 segment4LmidDocEnd segment4LmidDocEnd TRUE FALSE
314 FALSE 6 TextUnit_Word 0 docEnd docEndP1C 0 docEnd docEnd FALSE
315 FALSE 6 TextUnit_Word 1 docEnd docEndP1C 0 docEnd docEnd FALSE
316 FALSE 6 TextUnit_Word 5 docEnd docEndP1C 0 docEnd docEnd FALSE
317 TRUE 7 TextUnit_Word -5 midEmptySpace midEmptySpace -5 midDocEndLeft midDocEndLeft TRUE FALSE
318 TRUE 7 TextUnit_Word -1 midEmptySpace midEmptySpace -1 segment4LmidDocEnd segment4LmidDocEnd TRUE FALSE
319 TRUE 7 TextUnit_Word 0 midEmptySpace midEmptySpace 0 docEnd docEnd FALSE
320 TRUE 7 TextUnit_Word 1 midEmptySpace midEmptySpace 0 docEnd docEnd FALSE
321 TRUE 7 TextUnit_Word 5 midEmptySpace midEmptySpace 0 docEnd docEnd FALSE
322 FALSE 7 TextUnit_Word -5 midEmptySpace midEmptySpaceP1C -5 midDocEndLeft midDocEndLeft TRUE FALSE
323 FALSE 7 TextUnit_Word -1 midEmptySpace midEmptySpaceP1C -1 segment4LmidDocEnd segment4LmidDocEnd TRUE FALSE
324 FALSE 7 TextUnit_Word 0 midEmptySpace midEmptySpaceP1C 0 docEnd docEnd FALSE
325 FALSE 7 TextUnit_Word 1 midEmptySpace midEmptySpaceP1C 0 docEnd docEnd FALSE
326 FALSE 7 TextUnit_Word 5 midEmptySpace midEmptySpaceP1C 0 docEnd docEnd FALSE
327 TRUE 8 TextUnit_Word -5 bufferEnd bufferEnd -5 midDocEndLeft midDocEndLeft TRUE FALSE
328 TRUE 8 TextUnit_Word -1 bufferEnd bufferEnd -1 segment4LmidDocEnd segment4LmidDocEnd TRUE FALSE
329 TRUE 8 TextUnit_Word 0 bufferEnd bufferEnd 0 docEnd docEnd FALSE
330 TRUE 8 TextUnit_Word 1 bufferEnd bufferEnd 0 docEnd docEnd FALSE
331 TRUE 8 TextUnit_Word 5 bufferEnd bufferEnd 0 docEnd docEnd FALSE
332 FALSE 8 TextUnit_Word -5 bufferEnd endExclusive -5 midDocEndLeft midDocEndLeft TRUE FALSE
333 FALSE 8 TextUnit_Word -1 bufferEnd endExclusive -1 segment4LmidDocEnd segment4LmidDocEnd TRUE FALSE
334 FALSE 8 TextUnit_Word 0 bufferEnd endExclusive 0 docEnd docEnd FALSE
335 FALSE 8 TextUnit_Word 1 bufferEnd endExclusive 0 docEnd docEnd FALSE
336 FALSE 8 TextUnit_Word 5 bufferEnd endExclusive 0 docEnd docEnd FALSE
337 TRUE 9 TextUnit_Word -5 endExclusive endExclusive -5 midDocEndLeft midDocEndLeft TRUE FALSE
338 TRUE 9 TextUnit_Word -1 endExclusive endExclusive -1 segment4LmidDocEnd segment4LmidDocEnd TRUE FALSE
339 TRUE 9 TextUnit_Word 0 endExclusive endExclusive 0 docEnd docEnd FALSE
340 TRUE 9 TextUnit_Word 1 endExclusive endExclusive 0 docEnd docEnd FALSE
341 TRUE 9 TextUnit_Word 5 endExclusive endExclusive 0 docEnd docEnd FALSE