diff --git a/.github/actions/spelling/allow/allow.txt b/.github/actions/spelling/allow/allow.txt index eb9b2e277..e4abdb7d8 100644 --- a/.github/actions/spelling/allow/allow.txt +++ b/.github/actions/spelling/allow/allow.txt @@ -35,6 +35,9 @@ liga lje locl lorem +Llast +Lmid +Lorigin maxed mkmk mru diff --git a/src/buffer/out/textBuffer.cpp b/src/buffer/out/textBuffer.cpp index 58de15c20..466e38ecf 100644 --- a/src/buffer/out/textBuffer.cpp +++ b/src/buffer/out/textBuffer.cpp @@ -1057,9 +1057,10 @@ const DelimiterClass TextBuffer::_GetDelimiterClassAt(const COORD pos, const std // - accessibilityMode - when enabled, we continue expanding left until we are at the beginning of a readable word. // Otherwise, expand left until a character of a new delimiter class is found // (or a row boundary is encountered) +// - limitOptional - (optional) the last possible position in the buffer that can be explored. This can be used to improve performance. // Return Value: // - The COORD for the first character on the "word" (inclusive) -const COORD TextBuffer::GetWordStart(const COORD target, const std::wstring_view wordDelimiters, bool accessibilityMode) const +const COORD TextBuffer::GetWordStart(const COORD target, const std::wstring_view wordDelimiters, bool accessibilityMode, std::optional limitOptional) const { // Consider a buffer with this text in it: // " word other " @@ -1072,10 +1073,9 @@ const COORD TextBuffer::GetWordStart(const COORD target, const std::wstring_view // NOTE: the start anchor (this one) is inclusive, whereas the end anchor (GetWordEnd) is exclusive #pragma warning(suppress : 26496) - // GH#7664: Treat EndExclusive as EndInclusive so - // that it actually points to a space in the buffer auto copy{ target }; const auto bufferSize{ GetSize() }; + const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) }; if (target == bufferSize.Origin()) { // can't expand left @@ -1083,9 +1083,15 @@ const COORD TextBuffer::GetWordStart(const COORD target, const std::wstring_view } else if (target == bufferSize.EndExclusive()) { - // treat EndExclusive as EndInclusive + // GH#7664: Treat EndExclusive as EndInclusive so + // that it actually points to a space in the buffer copy = { bufferSize.RightInclusive(), bufferSize.BottomInclusive() }; } + else if (bufferSize.CompareInBounds(target, limit, true) >= 0) + { + // if at/past the limit --> clamp to limit + copy = *limitOptional; + } if (accessibilityMode) { @@ -1179,9 +1185,10 @@ const COORD TextBuffer::_GetWordStartForSelection(const COORD target, const std: // - accessibilityMode - when enabled, we continue expanding right until we are at the beginning of the next READABLE word // Otherwise, expand right until a character of a new delimiter class is found // (or a row boundary is encountered) +// - limitOptional - (optional) the last possible position in the buffer that can be explored. This can be used to improve performance. // Return Value: // - The COORD for the last character on the "word" (inclusive) -const COORD TextBuffer::GetWordEnd(const COORD target, const std::wstring_view wordDelimiters, bool accessibilityMode) const +const COORD TextBuffer::GetWordEnd(const COORD target, const std::wstring_view wordDelimiters, bool accessibilityMode, std::optional limitOptional) const { // Consider a buffer with this text in it: // " word other " @@ -1193,16 +1200,17 @@ const COORD TextBuffer::GetWordEnd(const COORD target, const std::wstring_view w // so the words in the example include ["word ", "other "] // NOTE: the end anchor (this one) is exclusive, whereas the start anchor (GetWordStart) is inclusive - // Already at the end. Can't move forward. - if (target == GetSize().EndExclusive()) + // Already at/past the limit. Can't move forward. + const auto bufferSize{ GetSize() }; + const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) }; + if (bufferSize.CompareInBounds(target, limit, true) >= 0) { return target; } if (accessibilityMode) { - const auto lastCharPos{ GetLastNonSpaceCharacter() }; - return _GetWordEndForAccessibility(target, wordDelimiters, lastCharPos); + return _GetWordEndForAccessibility(target, wordDelimiters, limit); } else { @@ -1215,44 +1223,46 @@ const COORD TextBuffer::GetWordEnd(const COORD target, const std::wstring_view w // Arguments: // - target - a COORD on the word you are currently on // - wordDelimiters - what characters are we considering for the separation of words -// - lastCharPos - the position of the last nonspace character in the text buffer (to improve performance) +// - limit - the last "valid" position in the text buffer (to improve performance) // Return Value: // - The COORD for the first character of the next readable "word". If no next word, return one past the end of the buffer -const COORD TextBuffer::_GetWordEndForAccessibility(const COORD target, const std::wstring_view wordDelimiters, const COORD lastCharPos) const +const COORD TextBuffer::_GetWordEndForAccessibility(const COORD target, const std::wstring_view wordDelimiters, const COORD limit) const { - const auto bufferSize = GetSize(); - COORD result = target; + const auto bufferSize{ GetSize() }; + COORD result{ target }; - // Check if we're already on/past the last RegularChar - if (bufferSize.CompareInBounds(result, lastCharPos, true) >= 0) + if (bufferSize.CompareInBounds(target, limit, true) >= 0) { - return bufferSize.EndExclusive(); + // if we're already on/past the last RegularChar, + // clamp result to that position + result = limit; + + // make the result exclusive + bufferSize.IncrementInBounds(result, true); } - - // ignore right boundary. Continue through readable text found - while (_GetDelimiterClassAt(result, wordDelimiters) == DelimiterClass::RegularChar) + else { - if (!bufferSize.IncrementInBounds(result, true)) + auto iter{ GetCellDataAt(result, bufferSize) }; + while (iter && iter.Pos() != limit && _GetDelimiterClassAt(iter.Pos(), wordDelimiters) == DelimiterClass::RegularChar) { - break; + // Iterate through readable text + ++iter; } - } - // we are already on/past the last RegularChar - if (bufferSize.CompareInBounds(result, lastCharPos, true) >= 0) - { - return bufferSize.EndExclusive(); - } - - // make sure we expand to the beginning of the NEXT word - while (_GetDelimiterClassAt(result, wordDelimiters) != DelimiterClass::RegularChar) - { - if (!bufferSize.IncrementInBounds(result, true)) + while (iter && iter.Pos() != limit && _GetDelimiterClassAt(iter.Pos(), wordDelimiters) != DelimiterClass::RegularChar) { - // we are at the EndInclusive COORD - // this signifies that we must include the last char in the buffer - // but the position of the COORD points to nothing - break; + // expand to the beginning of the NEXT word + ++iter; + } + + result = iter.Pos(); + + // Special case: we tried to move one past the end of the buffer, + // but iter prevented that (because that pos doesn't exist). + // Manually increment onto the EndExclusive point. + if (!iter) + { + bufferSize.IncrementInBounds(result, true); } } @@ -1345,18 +1355,20 @@ void TextBuffer::_PruneHyperlinks() // Arguments: // - pos - a COORD on the word you are currently on // - wordDelimiters - what characters are we considering for the separation of words -// - lastCharPos - the position of the last nonspace character in the text buffer (to improve performance) +// - limitOptional - (optional) the last possible position in the buffer that can be explored. This can be used to improve performance. // Return Value: // - true, if successfully updated pos. False, if we are unable to move (usually due to a buffer boundary) // - pos - The COORD for the first character on the "word" (inclusive) -bool TextBuffer::MoveToNextWord(COORD& pos, const std::wstring_view wordDelimiters, COORD lastCharPos) const +bool TextBuffer::MoveToNextWord(COORD& pos, const std::wstring_view wordDelimiters, std::optional limitOptional) const { // move to the beginning of the next word // NOTE: _GetWordEnd...() returns the exclusive position of the "end of the word" // This is also the inclusive start of the next word. - auto copy{ _GetWordEndForAccessibility(pos, wordDelimiters, lastCharPos) }; + const auto bufferSize{ GetSize() }; + const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) }; + const auto copy{ _GetWordEndForAccessibility(pos, wordDelimiters, limit) }; - if (copy == GetSize().EndExclusive()) + if (bufferSize.CompareInBounds(copy, limit, true) >= 0) { return false; } @@ -1393,19 +1405,23 @@ bool TextBuffer::MoveToPreviousWord(COORD& pos, std::wstring_view wordDelimiters // - Update pos to be the beginning of the current glyph/character. This is used for accessibility // Arguments: // - pos - a COORD on the word you are currently on +// - limitOptional - (optional) the last possible position in the buffer that can be explored. This can be used to improve performance. // Return Value: // - pos - The COORD for the first cell of the current glyph (inclusive) -const til::point TextBuffer::GetGlyphStart(const til::point pos) const +const til::point TextBuffer::GetGlyphStart(const til::point pos, std::optional limitOptional) const { COORD resultPos = pos; const auto bufferSize = GetSize(); + const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) }; - if (resultPos == bufferSize.EndExclusive()) + // Clamp pos to limit + if (bufferSize.CompareInBounds(resultPos, limit, true) > 0) { - bufferSize.DecrementInBounds(resultPos, true); + resultPos = limit; } - if (resultPos != bufferSize.EndExclusive() && GetCellDataAt(resultPos)->DbcsAttr().IsTrailing()) + // limit is exclusive, so we need to move back to be within valid bounds + if (resultPos != limit && GetCellDataAt(resultPos)->DbcsAttr().IsTrailing()) { bufferSize.DecrementInBounds(resultPos, true); } @@ -1419,12 +1435,19 @@ const til::point TextBuffer::GetGlyphStart(const til::point pos) const // - pos - a COORD on the word you are currently on // Return Value: // - pos - The COORD for the last cell of the current glyph (exclusive) -const til::point TextBuffer::GetGlyphEnd(const til::point pos) const +const til::point TextBuffer::GetGlyphEnd(const til::point pos, std::optional limitOptional) const { COORD resultPos = pos; - const auto bufferSize = GetSize(); - if (resultPos != bufferSize.EndExclusive() && GetCellDataAt(resultPos)->DbcsAttr().IsLeading()) + const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) }; + + // Clamp pos to limit + if (bufferSize.CompareInBounds(resultPos, limit, true) > 0) + { + resultPos = limit; + } + + if (resultPos != limit && GetCellDataAt(resultPos)->DbcsAttr().IsLeading()) { bufferSize.IncrementInBounds(resultPos, true); } @@ -1438,29 +1461,43 @@ const til::point TextBuffer::GetGlyphEnd(const til::point pos) const // - Update pos to be the beginning of the next glyph/character. This is used for accessibility // Arguments: // - pos - a COORD on the word you are currently on -// - allowBottomExclusive - allow the nonexistent end-of-buffer cell to be encountered +// - allowExclusiveEnd - allow result to be the exclusive limit (one past limit) +// - limit - boundaries for the iterator to operate within // Return Value: // - true, if successfully updated pos. False, if we are unable to move (usually due to a buffer boundary) // - pos - The COORD for the first cell of the current glyph (inclusive) -bool TextBuffer::MoveToNextGlyph(til::point& pos, bool allowBottomExclusive) const +bool TextBuffer::MoveToNextGlyph(til::point& pos, bool allowExclusiveEnd, std::optional limitOptional) const { - COORD resultPos = pos; const auto bufferSize = GetSize(); + const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) }; - if (resultPos == GetSize().EndExclusive()) + const auto distanceToLimit{ bufferSize.CompareInBounds(pos, limit, true) }; + if (distanceToLimit >= 0) { - // we're already at the end + // Corner Case: we're on/past the limit + // Clamp us to the limit + pos = limit; + return false; + } + else if (!allowExclusiveEnd && distanceToLimit == -1) + { + // Corner Case: we're just before the limit + // and we are not allowed onto the exclusive end. + // Fail to move. return false; } - // try to move. If we can't, we're done. - const bool success = bufferSize.IncrementInBounds(resultPos, allowBottomExclusive); - if (resultPos != bufferSize.EndExclusive() && GetCellDataAt(resultPos)->DbcsAttr().IsTrailing()) + // Try to move forward, but if we hit the buffer boundary, we fail to move. + auto iter{ GetCellDataAt(pos, bufferSize) }; + const bool success{ ++iter }; + + // Move again if we're on a wide glyph + if (success && iter->DbcsAttr().IsTrailing()) { - bufferSize.IncrementInBounds(resultPos, allowBottomExclusive); + ++iter; } - pos = resultPos; + pos = iter.Pos(); return success; } @@ -1471,12 +1508,21 @@ bool TextBuffer::MoveToNextGlyph(til::point& pos, bool allowBottomExclusive) con // Return Value: // - true, if successfully updated pos. False, if we are unable to move (usually due to a buffer boundary) // - pos - The COORD for the first cell of the previous glyph (inclusive) -bool TextBuffer::MoveToPreviousGlyph(til::point& pos) const +bool TextBuffer::MoveToPreviousGlyph(til::point& pos, std::optional limitOptional) const { COORD resultPos = pos; + const auto bufferSize = GetSize(); + const auto limit{ limitOptional.value_or(bufferSize.EndExclusive()) }; + + if (bufferSize.CompareInBounds(pos, limit, true) > 0) + { + // we're past the end + // clamp us to the limit + pos = limit; + return true; + } // try to move. If we can't, we're done. - const auto bufferSize = GetSize(); const bool success = bufferSize.DecrementInBounds(resultPos, true); if (resultPos != bufferSize.EndExclusive() && GetCellDataAt(resultPos)->DbcsAttr().IsLeading()) { diff --git a/src/buffer/out/textBuffer.hpp b/src/buffer/out/textBuffer.hpp index 468a9fc4f..3c0e1ad2a 100644 --- a/src/buffer/out/textBuffer.hpp +++ b/src/buffer/out/textBuffer.hpp @@ -141,15 +141,15 @@ public: Microsoft::Console::Render::IRenderTarget& GetRenderTarget() noexcept; - const COORD GetWordStart(const COORD target, const std::wstring_view wordDelimiters, bool accessibilityMode = false) const; - const COORD GetWordEnd(const COORD target, const std::wstring_view wordDelimiters, bool accessibilityMode = false) const; - bool MoveToNextWord(COORD& pos, const std::wstring_view wordDelimiters, COORD lastCharPos) const; + const COORD GetWordStart(const COORD target, const std::wstring_view wordDelimiters, bool accessibilityMode = false, std::optional limitOptional = std::nullopt) const; + const COORD GetWordEnd(const COORD target, const std::wstring_view wordDelimiters, bool accessibilityMode = false, std::optional limitOptional = std::nullopt) const; + bool MoveToNextWord(COORD& pos, const std::wstring_view wordDelimiters, std::optional limitOptional = std::nullopt) const; bool MoveToPreviousWord(COORD& pos, const std::wstring_view wordDelimiters) const; - const til::point GetGlyphStart(const til::point pos) const; - const til::point GetGlyphEnd(const til::point pos) const; - bool MoveToNextGlyph(til::point& pos, bool allowBottomExclusive = false) const; - bool MoveToPreviousGlyph(til::point& pos) const; + const til::point GetGlyphStart(const til::point pos, std::optional limitOptional = std::nullopt) const; + const til::point GetGlyphEnd(const til::point pos, std::optional limitOptional = std::nullopt) const; + bool MoveToNextGlyph(til::point& pos, bool allowBottomExclusive = false, std::optional limitOptional = std::nullopt) const; + bool MoveToPreviousGlyph(til::point& pos, std::optional limitOptional = std::nullopt) const; const std::vector GetTextRects(COORD start, COORD end, bool blockSelection, bool bufferCoordinates) const; @@ -242,7 +242,7 @@ private: const DelimiterClass _GetDelimiterClassAt(const COORD pos, const std::wstring_view wordDelimiters) const; const COORD _GetWordStartForAccessibility(const COORD target, const std::wstring_view wordDelimiters) const; const COORD _GetWordStartForSelection(const COORD target, const std::wstring_view wordDelimiters) const; - const COORD _GetWordEndForAccessibility(const COORD target, const std::wstring_view wordDelimiters, const COORD lastCharPos) const; + const COORD _GetWordEndForAccessibility(const COORD target, const std::wstring_view wordDelimiters, const COORD limit) const; const COORD _GetWordEndForSelection(const COORD target, const std::wstring_view wordDelimiters) const; void _PruneHyperlinks(); diff --git a/src/interactivity/win32/ut_interactivity_win32/GeneratedUiaTextRangeMovementTests.g.cpp b/src/interactivity/win32/ut_interactivity_win32/GeneratedUiaTextRangeMovementTests.g.cpp index e571716d0..34cffaf97 100644 --- a/src/interactivity/win32/ut_interactivity_win32/GeneratedUiaTextRangeMovementTests.g.cpp +++ b/src/interactivity/win32/ut_interactivity_win32/GeneratedUiaTextRangeMovementTests.g.cpp @@ -9,29 +9,25 @@ constexpr til::rectangle bufferSize{ 0, 0, 80, 300 }; constexpr short midX{ 40 }; constexpr short midY{ 150 }; constexpr short midPopulatedY{ 75 }; +constexpr short segment0{ 0 }; +constexpr short segment1{ 16 }; +constexpr short segment2{ 32 }; +constexpr short segment3{ 48 }; +constexpr short segment4{ 64 }; constexpr til::point origin{ 0, 0 }; constexpr til::point midTop{ midX, 0 }; constexpr til::point midHistory{ midX, midPopulatedY }; constexpr til::point midDocEnd{ midX, midY }; -constexpr til::point lastCharPos{ 79, midY }; +constexpr til::point lastCharPos{ 72, midY }; constexpr til::point docEnd{ 0, midY + 1 }; constexpr til::point midEmptySpace{ midX, midY + midPopulatedY }; constexpr til::point bufferEnd{ 79, 299 }; constexpr til::point endExclusive{ 0, 300 }; - -constexpr til::point bufferEndLeft{ bufferSize.left(), bufferEnd.y() }; -constexpr auto bufferEndM1C{ point_offset_by_char(bufferEnd, bufferSize, -1) }; -constexpr auto bufferEndM1L{ point_offset_by_line(bufferEnd, bufferSize, -1) }; -constexpr auto bufferEndM4C{ point_offset_by_char(bufferEnd, bufferSize, -4) }; -constexpr auto bufferEndM4L{ point_offset_by_line(bufferEnd, bufferSize, -4) }; -constexpr auto bufferEndM5C{ point_offset_by_char(bufferEnd, bufferSize, -5) }; -constexpr auto bufferEndM5L{ point_offset_by_line(bufferEnd, bufferSize, -5) }; -constexpr til::point docEndLeft{ bufferSize.left(), docEnd.y() }; constexpr auto docEndM1C{ point_offset_by_char(docEnd, bufferSize, -1) }; -constexpr auto docEndM4L{ point_offset_by_line(docEnd, bufferSize, -4) }; +constexpr auto docEndM1L{ point_offset_by_line(docEnd, bufferSize, -1) }; constexpr auto docEndM5C{ point_offset_by_char(docEnd, bufferSize, -5) }; +constexpr auto docEndM5L{ point_offset_by_line(docEnd, bufferSize, -5) }; constexpr auto docEndP1C{ point_offset_by_char(docEnd, bufferSize, 1) }; - constexpr til::point lastCharPosLeft{ bufferSize.left(), lastCharPos.y() }; constexpr auto lastCharPosM1C{ point_offset_by_char(lastCharPos, bufferSize, -1) }; constexpr auto lastCharPosM1L{ point_offset_by_line(lastCharPos, bufferSize, -1) }; @@ -40,7 +36,9 @@ constexpr auto lastCharPosM4L{ point_offset_by_line(lastCharPos, bufferSize, -4) constexpr auto lastCharPosM5C{ point_offset_by_char(lastCharPos, bufferSize, -5) }; constexpr auto lastCharPosM5L{ point_offset_by_line(lastCharPos, bufferSize, -5) }; constexpr auto lastCharPosP1C{ point_offset_by_char(lastCharPos, bufferSize, 1) }; - +constexpr auto lastCharPosP2C{ point_offset_by_char(lastCharPos, bufferSize, 2) }; +constexpr auto lastCharPosP5C{ point_offset_by_char(lastCharPos, bufferSize, 5) }; +constexpr auto lastCharPosP6C{ point_offset_by_char(lastCharPos, bufferSize, 6) }; constexpr til::point midDocEndLeft{ bufferSize.left(), midDocEnd.y() }; constexpr auto midDocEndM1C{ point_offset_by_char(midDocEnd, bufferSize, -1) }; constexpr auto midDocEndM1L{ point_offset_by_line(midDocEnd, bufferSize, -1) }; @@ -52,7 +50,6 @@ constexpr auto midDocEndP1C{ point_offset_by_char(midDocEnd, bufferSize, 1) }; constexpr auto midDocEndP2C{ point_offset_by_char(midDocEnd, bufferSize, 2) }; constexpr auto midDocEndP5C{ point_offset_by_char(midDocEnd, bufferSize, 5) }; constexpr auto midDocEndP6C{ point_offset_by_char(midDocEnd, bufferSize, 6) }; - constexpr auto midEmptySpaceP1C{ point_offset_by_char(midEmptySpace, bufferSize, 1) }; constexpr til::point midHistoryLeft{ bufferSize.left(), midHistory.y() }; constexpr auto midHistoryM1C{ point_offset_by_char(midHistory, bufferSize, -1) }; @@ -86,6 +83,29 @@ constexpr auto originP5C{ point_offset_by_char(origin, bufferSize, 5) }; constexpr auto originP5L{ point_offset_by_line(origin, bufferSize, 5) }; constexpr auto originP6C{ point_offset_by_char(origin, bufferSize, 6) }; constexpr auto originP6L{ point_offset_by_line(origin, bufferSize, 6) }; +constexpr til::point segment0LmidTopP1L{ segment0, midTopP1L.y() }; +constexpr til::point segment1LmidDocEnd{ segment1, midDocEnd.y() }; +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 segment2LmidHistory{ segment2, midHistory.y() }; +constexpr til::point segment2LmidHistoryP1L{ segment2, midHistoryP1L.y() }; +constexpr til::point segment2LmidTop{ segment2, midTop.y() }; +constexpr til::point segment2LmidTopP1L{ segment2, midTopP1L.y() }; +constexpr til::point segment3LmidDocEnd{ segment3, midDocEnd.y() }; +constexpr til::point segment3LmidDocEndM1L{ segment3, midDocEndM1L.y() }; +constexpr til::point segment3LmidHistory{ segment3, midHistory.y() }; +constexpr til::point segment3LmidHistoryM1L{ segment3, midHistoryM1L.y() }; +constexpr til::point segment3LmidHistoryP1L{ segment3, midHistoryP1L.y() }; +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 { TextUnit unit; @@ -107,7 +127,7 @@ struct GeneratedMovementTest bool skip; }; -static constexpr std::array s_movementTests{ +static constexpr std::array s_movementTests{ GeneratedMovementTest{ L"Move degenerate range at position 1 -5 times by Character", GeneratedMovementTestInput{ @@ -873,8 +893,8 @@ static constexpr std::array s_movementTests{ origin }, GeneratedMovementTestExpected{ 1, - endExclusive, - endExclusive }, + docEnd, + docEnd }, false }, GeneratedMovementTest{ L"Move degenerate range at position 1 5 times by Document", @@ -885,8 +905,8 @@ static constexpr std::array s_movementTests{ origin }, GeneratedMovementTestExpected{ 1, - endExclusive, - endExclusive }, + docEnd, + docEnd }, false }, GeneratedMovementTest{ L"Move non-degenerate range at position 1 -5 times by Document", @@ -898,7 +918,7 @@ static constexpr std::array s_movementTests{ GeneratedMovementTestExpected{ 0, origin, - endExclusive }, + docEnd }, false }, GeneratedMovementTest{ L"Move non-degenerate range at position 1 -1 times by Document", @@ -910,7 +930,7 @@ static constexpr std::array s_movementTests{ GeneratedMovementTestExpected{ 0, origin, - endExclusive }, + docEnd }, false }, GeneratedMovementTest{ L"Move non-degenerate range at position 1 0 times by Document", @@ -922,7 +942,7 @@ static constexpr std::array s_movementTests{ GeneratedMovementTestExpected{ 0, origin, - endExclusive }, + docEnd }, false }, GeneratedMovementTest{ L"Move non-degenerate range at position 1 1 times by Document", @@ -934,7 +954,7 @@ static constexpr std::array s_movementTests{ GeneratedMovementTestExpected{ 0, origin, - endExclusive }, + docEnd }, false }, GeneratedMovementTest{ L"Move non-degenerate range at position 1 5 times by Document", @@ -946,7 +966,7 @@ static constexpr std::array s_movementTests{ GeneratedMovementTestExpected{ 0, origin, - endExclusive }, + docEnd }, false }, GeneratedMovementTest{ L"Move degenerate range at position 2 -5 times by Document", @@ -993,8 +1013,8 @@ static constexpr std::array s_movementTests{ midTop }, GeneratedMovementTestExpected{ 1, - endExclusive, - endExclusive }, + docEnd, + docEnd }, false }, GeneratedMovementTest{ L"Move degenerate range at position 2 5 times by Document", @@ -1005,8 +1025,8 @@ static constexpr std::array s_movementTests{ midTop }, GeneratedMovementTestExpected{ 1, - endExclusive, - endExclusive }, + docEnd, + docEnd }, false }, GeneratedMovementTest{ L"Move non-degenerate range at position 2 -5 times by Document", @@ -1018,7 +1038,7 @@ static constexpr std::array s_movementTests{ GeneratedMovementTestExpected{ 0, origin, - endExclusive }, + docEnd }, false }, GeneratedMovementTest{ L"Move non-degenerate range at position 2 -1 times by Document", @@ -1030,7 +1050,7 @@ static constexpr std::array s_movementTests{ GeneratedMovementTestExpected{ 0, origin, - endExclusive }, + docEnd }, false }, GeneratedMovementTest{ L"Move non-degenerate range at position 2 0 times by Document", @@ -1042,7 +1062,7 @@ static constexpr std::array s_movementTests{ GeneratedMovementTestExpected{ 0, origin, - endExclusive }, + docEnd }, false }, GeneratedMovementTest{ L"Move non-degenerate range at position 2 1 times by Document", @@ -1054,7 +1074,7 @@ static constexpr std::array s_movementTests{ GeneratedMovementTestExpected{ 0, origin, - endExclusive }, + docEnd }, false }, GeneratedMovementTest{ L"Move non-degenerate range at position 2 5 times by Document", @@ -1066,7 +1086,7 @@ static constexpr std::array s_movementTests{ GeneratedMovementTestExpected{ 0, origin, - endExclusive }, + docEnd }, false }, GeneratedMovementTest{ L"Move degenerate range at position 3 -5 times by Document", @@ -1113,8 +1133,8 @@ static constexpr std::array s_movementTests{ midHistory }, GeneratedMovementTestExpected{ 1, - endExclusive, - endExclusive }, + docEnd, + docEnd }, false }, GeneratedMovementTest{ L"Move degenerate range at position 3 5 times by Document", @@ -1125,8 +1145,8 @@ static constexpr std::array s_movementTests{ midHistory }, GeneratedMovementTestExpected{ 1, - endExclusive, - endExclusive }, + docEnd, + docEnd }, false }, GeneratedMovementTest{ L"Move non-degenerate range at position 3 -5 times by Document", @@ -1138,7 +1158,7 @@ static constexpr std::array s_movementTests{ GeneratedMovementTestExpected{ 0, origin, - endExclusive }, + docEnd }, false }, GeneratedMovementTest{ L"Move non-degenerate range at position 3 -1 times by Document", @@ -1150,7 +1170,7 @@ static constexpr std::array s_movementTests{ GeneratedMovementTestExpected{ 0, origin, - endExclusive }, + docEnd }, false }, GeneratedMovementTest{ L"Move non-degenerate range at position 3 0 times by Document", @@ -1162,7 +1182,7 @@ static constexpr std::array s_movementTests{ GeneratedMovementTestExpected{ 0, origin, - endExclusive }, + docEnd }, false }, GeneratedMovementTest{ L"Move non-degenerate range at position 3 1 times by Document", @@ -1174,7 +1194,7 @@ static constexpr std::array s_movementTests{ GeneratedMovementTestExpected{ 0, origin, - endExclusive }, + docEnd }, false }, GeneratedMovementTest{ L"Move non-degenerate range at position 3 5 times by Document", @@ -1186,7 +1206,7 @@ static constexpr std::array s_movementTests{ GeneratedMovementTestExpected{ 0, origin, - endExclusive }, + docEnd }, false }, GeneratedMovementTest{ L"Move degenerate range at position 8 -5 times by Character", @@ -1197,8 +1217,8 @@ static constexpr std::array s_movementTests{ bufferEnd }, GeneratedMovementTestExpected{ -5, - bufferEndM5C, - bufferEndM5C }, + docEndM5C, + docEndM5C }, false }, GeneratedMovementTest{ L"Move degenerate range at position 8 -1 times by Character", @@ -1209,8 +1229,8 @@ static constexpr std::array s_movementTests{ bufferEnd }, GeneratedMovementTestExpected{ -1, - bufferEndM1C, - bufferEndM1C }, + docEndM1C, + docEndM1C }, false }, GeneratedMovementTest{ L"Move degenerate range at position 8 0 times by Character", @@ -1221,8 +1241,8 @@ static constexpr std::array s_movementTests{ bufferEnd }, GeneratedMovementTestExpected{ 0, - bufferEnd, - bufferEnd }, + docEnd, + docEnd }, false }, GeneratedMovementTest{ L"Move degenerate range at position 8 1 times by Character", @@ -1232,10 +1252,10 @@ static constexpr std::array s_movementTests{ bufferEnd, bufferEnd }, GeneratedMovementTestExpected{ - 1, - endExclusive, - endExclusive }, - true }, + 0, + docEnd, + docEnd }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 8 5 times by Character", GeneratedMovementTestInput{ @@ -1244,10 +1264,10 @@ static constexpr std::array s_movementTests{ bufferEnd, bufferEnd }, GeneratedMovementTestExpected{ - 1, - endExclusive, - endExclusive }, - true }, + 0, + docEnd, + docEnd }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 8 -5 times by Character", GeneratedMovementTestInput{ @@ -1257,8 +1277,8 @@ static constexpr std::array s_movementTests{ endExclusive }, GeneratedMovementTestExpected{ -5, - bufferEndM5C, - bufferEndM4C }, + docEndM5C, + docEndM5C }, false }, GeneratedMovementTest{ L"Move non-degenerate range at position 8 -1 times by Character", @@ -1269,8 +1289,8 @@ static constexpr std::array s_movementTests{ endExclusive }, GeneratedMovementTestExpected{ -1, - bufferEndM1C, - bufferEnd }, + docEndM1C, + docEndM1C }, false }, GeneratedMovementTest{ L"Move non-degenerate range at position 8 0 times by Character", @@ -1281,8 +1301,8 @@ static constexpr std::array s_movementTests{ endExclusive }, GeneratedMovementTestExpected{ 0, - bufferEnd, - endExclusive }, + docEnd, + docEnd }, false }, GeneratedMovementTest{ L"Move non-degenerate range at position 8 1 times by Character", @@ -1293,8 +1313,8 @@ static constexpr std::array s_movementTests{ endExclusive }, GeneratedMovementTestExpected{ 0, - bufferEnd, - endExclusive }, + docEnd, + docEnd }, false }, GeneratedMovementTest{ L"Move non-degenerate range at position 8 5 times by Character", @@ -1305,8 +1325,8 @@ static constexpr std::array s_movementTests{ endExclusive }, GeneratedMovementTestExpected{ 0, - bufferEnd, - endExclusive }, + docEnd, + docEnd }, false }, GeneratedMovementTest{ L"Move degenerate range at position 8 -5 times by Line", @@ -1317,8 +1337,8 @@ static constexpr std::array s_movementTests{ bufferEnd }, GeneratedMovementTestExpected{ -5, - bufferEndM4L, - bufferEndM4L }, + docEndM5L, + docEndM5L }, false }, GeneratedMovementTest{ L"Move degenerate range at position 8 -1 times by Line", @@ -1329,8 +1349,8 @@ static constexpr std::array s_movementTests{ bufferEnd }, GeneratedMovementTestExpected{ -1, - bufferEndLeft, - bufferEndLeft }, + docEndM1L, + docEndM1L }, false }, GeneratedMovementTest{ L"Move degenerate range at position 8 0 times by Line", @@ -1341,8 +1361,8 @@ static constexpr std::array s_movementTests{ bufferEnd }, GeneratedMovementTestExpected{ 0, - bufferEnd, - bufferEnd }, + docEnd, + docEnd }, false }, GeneratedMovementTest{ L"Move degenerate range at position 8 1 times by Line", @@ -1352,10 +1372,10 @@ static constexpr std::array s_movementTests{ bufferEnd, bufferEnd }, GeneratedMovementTestExpected{ - 1, - endExclusive, - endExclusive }, - true }, + 0, + docEnd, + docEnd }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 8 5 times by Line", GeneratedMovementTestInput{ @@ -1364,10 +1384,10 @@ static constexpr std::array s_movementTests{ bufferEnd, bufferEnd }, GeneratedMovementTestExpected{ - 1, - endExclusive, - endExclusive }, - true }, + 0, + docEnd, + docEnd }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 8 -5 times by Line", GeneratedMovementTestInput{ @@ -1377,9 +1397,9 @@ static constexpr std::array s_movementTests{ endExclusive }, GeneratedMovementTestExpected{ -5, - bufferEndM5L, - bufferEndM4L }, - true }, + docEndM5L, + docEndM5L }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 8 -1 times by Line", GeneratedMovementTestInput{ @@ -1389,9 +1409,9 @@ static constexpr std::array s_movementTests{ endExclusive }, GeneratedMovementTestExpected{ -1, - bufferEndM1L, - bufferEndLeft }, - true }, + docEndM1L, + docEndM1L }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 8 0 times by Line", GeneratedMovementTestInput{ @@ -1401,9 +1421,9 @@ static constexpr std::array s_movementTests{ endExclusive }, GeneratedMovementTestExpected{ 0, - bufferEndLeft, - endExclusive }, - true }, + docEnd, + docEnd }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 8 1 times by Line", GeneratedMovementTestInput{ @@ -1413,9 +1433,9 @@ static constexpr std::array s_movementTests{ endExclusive }, GeneratedMovementTestExpected{ 0, - bufferEndLeft, - endExclusive }, - true }, + docEnd, + docEnd }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 8 5 times by Line", GeneratedMovementTestInput{ @@ -1425,9 +1445,9 @@ static constexpr std::array s_movementTests{ endExclusive }, GeneratedMovementTestExpected{ 0, - bufferEndLeft, - endExclusive }, - true }, + docEnd, + docEnd }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 8 -5 times by Document", GeneratedMovementTestInput{ @@ -1461,8 +1481,8 @@ static constexpr std::array s_movementTests{ bufferEnd }, GeneratedMovementTestExpected{ 0, - bufferEnd, - bufferEnd }, + docEnd, + docEnd }, false }, GeneratedMovementTest{ L"Move degenerate range at position 8 1 times by Document", @@ -1472,10 +1492,10 @@ static constexpr std::array s_movementTests{ bufferEnd, bufferEnd }, GeneratedMovementTestExpected{ - 1, - endExclusive, - endExclusive }, - true }, + 0, + docEnd, + docEnd }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 8 5 times by Document", GeneratedMovementTestInput{ @@ -1484,10 +1504,10 @@ static constexpr std::array s_movementTests{ bufferEnd, bufferEnd }, GeneratedMovementTestExpected{ - 1, - endExclusive, - endExclusive }, - true }, + 0, + docEnd, + docEnd }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 8 -5 times by Document", GeneratedMovementTestInput{ @@ -1496,10 +1516,10 @@ static constexpr std::array s_movementTests{ bufferEnd, endExclusive }, GeneratedMovementTestExpected{ - 0, + -1, origin, - endExclusive }, - true }, + origin }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 8 -1 times by Document", GeneratedMovementTestInput{ @@ -1508,10 +1528,10 @@ static constexpr std::array s_movementTests{ bufferEnd, endExclusive }, GeneratedMovementTestExpected{ - 0, + -1, origin, - endExclusive }, - true }, + origin }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 8 0 times by Document", GeneratedMovementTestInput{ @@ -1521,9 +1541,9 @@ static constexpr std::array s_movementTests{ endExclusive }, GeneratedMovementTestExpected{ 0, - origin, - endExclusive }, - true }, + docEnd, + docEnd }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 8 1 times by Document", GeneratedMovementTestInput{ @@ -1533,9 +1553,9 @@ static constexpr std::array s_movementTests{ endExclusive }, GeneratedMovementTestExpected{ 0, - origin, - endExclusive }, - true }, + docEnd, + docEnd }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 8 5 times by Document", GeneratedMovementTestInput{ @@ -1545,9 +1565,9 @@ static constexpr std::array s_movementTests{ endExclusive }, GeneratedMovementTestExpected{ 0, - origin, - endExclusive }, - true }, + docEnd, + docEnd }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 9 -5 times by Character", GeneratedMovementTestInput{ @@ -1557,8 +1577,8 @@ static constexpr std::array s_movementTests{ endExclusive }, GeneratedMovementTestExpected{ -5, - bufferEndM4C, - bufferEndM4C }, + docEndM5C, + docEndM5C }, false }, GeneratedMovementTest{ L"Move degenerate range at position 9 -1 times by Character", @@ -1569,8 +1589,8 @@ static constexpr std::array s_movementTests{ endExclusive }, GeneratedMovementTestExpected{ -1, - bufferEnd, - bufferEnd }, + docEndM1C, + docEndM1C }, false }, GeneratedMovementTest{ L"Move degenerate range at position 9 0 times by Character", @@ -1581,8 +1601,8 @@ static constexpr std::array s_movementTests{ endExclusive }, GeneratedMovementTestExpected{ 0, - endExclusive, - endExclusive }, + docEnd, + docEnd }, false }, GeneratedMovementTest{ L"Move degenerate range at position 9 1 times by Character", @@ -1593,8 +1613,8 @@ static constexpr std::array s_movementTests{ endExclusive }, GeneratedMovementTestExpected{ 0, - endExclusive, - endExclusive }, + docEnd, + docEnd }, false }, GeneratedMovementTest{ L"Move degenerate range at position 9 5 times by Character", @@ -1605,8 +1625,8 @@ static constexpr std::array s_movementTests{ endExclusive }, GeneratedMovementTestExpected{ 0, - endExclusive, - endExclusive }, + docEnd, + docEnd }, false }, GeneratedMovementTest{ L"Move degenerate range at position 9 -5 times by Line", @@ -1617,8 +1637,8 @@ static constexpr std::array s_movementTests{ endExclusive }, GeneratedMovementTestExpected{ -5, - bufferEndM4L, - bufferEndM4L }, + docEndM5L, + docEndM5L }, false }, GeneratedMovementTest{ L"Move degenerate range at position 9 -1 times by Line", @@ -1629,8 +1649,8 @@ static constexpr std::array s_movementTests{ endExclusive }, GeneratedMovementTestExpected{ -1, - bufferEndLeft, - bufferEndLeft }, + docEndM1L, + docEndM1L }, false }, GeneratedMovementTest{ L"Move degenerate range at position 9 0 times by Line", @@ -1641,8 +1661,8 @@ static constexpr std::array s_movementTests{ endExclusive }, GeneratedMovementTestExpected{ 0, - endExclusive, - endExclusive }, + docEnd, + docEnd }, false }, GeneratedMovementTest{ L"Move degenerate range at position 9 1 times by Line", @@ -1653,8 +1673,8 @@ static constexpr std::array s_movementTests{ endExclusive }, GeneratedMovementTestExpected{ 0, - endExclusive, - endExclusive }, + docEnd, + docEnd }, false }, GeneratedMovementTest{ L"Move degenerate range at position 9 5 times by Line", @@ -1665,8 +1685,8 @@ static constexpr std::array s_movementTests{ endExclusive }, GeneratedMovementTestExpected{ 0, - endExclusive, - endExclusive }, + docEnd, + docEnd }, false }, GeneratedMovementTest{ L"Move degenerate range at position 9 -5 times by Document", @@ -1701,8 +1721,8 @@ static constexpr std::array s_movementTests{ endExclusive }, GeneratedMovementTestExpected{ 0, - endExclusive, - endExclusive }, + docEnd, + docEnd }, false }, GeneratedMovementTest{ L"Move degenerate range at position 9 1 times by Document", @@ -1713,8 +1733,8 @@ static constexpr std::array s_movementTests{ endExclusive }, GeneratedMovementTestExpected{ 0, - endExclusive, - endExclusive }, + docEnd, + docEnd }, false }, GeneratedMovementTest{ L"Move degenerate range at position 9 5 times by Document", @@ -1725,8 +1745,8 @@ static constexpr std::array s_movementTests{ endExclusive }, GeneratedMovementTestExpected{ 0, - endExclusive, - endExclusive }, + docEnd, + docEnd }, false }, GeneratedMovementTest{ L"Move degenerate range at position 4 -5 times by Character", @@ -1739,7 +1759,7 @@ static constexpr std::array s_movementTests{ -5, midDocEndM5C, midDocEndM5C }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 4 -1 times by Character", GeneratedMovementTestInput{ @@ -1751,7 +1771,7 @@ static constexpr std::array s_movementTests{ -1, midDocEndM1C, midDocEndM1C }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 4 0 times by Character", GeneratedMovementTestInput{ @@ -1763,7 +1783,7 @@ static constexpr std::array s_movementTests{ 0, midDocEnd, midDocEnd }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 4 1 times by Character", GeneratedMovementTestInput{ @@ -1775,7 +1795,7 @@ static constexpr std::array s_movementTests{ 1, midDocEndP1C, midDocEndP1C }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 4 5 times by Character", GeneratedMovementTestInput{ @@ -1787,7 +1807,7 @@ static constexpr std::array s_movementTests{ 5, midDocEndP5C, midDocEndP5C }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 4 -5 times by Character", GeneratedMovementTestInput{ @@ -1799,7 +1819,7 @@ static constexpr std::array s_movementTests{ -5, midDocEndM5C, midDocEndM4C }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 4 -1 times by Character", GeneratedMovementTestInput{ @@ -1811,7 +1831,7 @@ static constexpr std::array s_movementTests{ -1, midDocEndM1C, midDocEnd }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 4 0 times by Character", GeneratedMovementTestInput{ @@ -1823,7 +1843,7 @@ static constexpr std::array s_movementTests{ 0, midDocEnd, midDocEndP1C }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 4 1 times by Character", GeneratedMovementTestInput{ @@ -1835,7 +1855,7 @@ static constexpr std::array s_movementTests{ 1, midDocEndP1C, midDocEndP2C }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 4 5 times by Character", GeneratedMovementTestInput{ @@ -1847,7 +1867,7 @@ static constexpr std::array s_movementTests{ 5, midDocEndP5C, midDocEndP6C }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 4 -5 times by Line", GeneratedMovementTestInput{ @@ -1859,7 +1879,7 @@ static constexpr std::array s_movementTests{ -5, midDocEndM4L, midDocEndM4L }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 4 -1 times by Line", GeneratedMovementTestInput{ @@ -1871,7 +1891,7 @@ static constexpr std::array s_movementTests{ -1, midDocEndLeft, midDocEndLeft }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 4 0 times by Line", GeneratedMovementTestInput{ @@ -1883,7 +1903,7 @@ static constexpr std::array s_movementTests{ 0, midDocEnd, midDocEnd }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 4 1 times by Line", GeneratedMovementTestInput{ @@ -1895,7 +1915,7 @@ static constexpr std::array s_movementTests{ 1, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 4 5 times by Line", GeneratedMovementTestInput{ @@ -1907,7 +1927,7 @@ static constexpr std::array s_movementTests{ 1, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 4 -5 times by Line", GeneratedMovementTestInput{ @@ -1919,7 +1939,7 @@ static constexpr std::array s_movementTests{ -5, midDocEndM5L, midDocEndM4L }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 4 -1 times by Line", GeneratedMovementTestInput{ @@ -1931,7 +1951,7 @@ static constexpr std::array s_movementTests{ -1, midDocEndM1L, midDocEndLeft }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 4 0 times by Line", GeneratedMovementTestInput{ @@ -1943,7 +1963,7 @@ static constexpr std::array s_movementTests{ 0, midDocEndLeft, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 4 1 times by Line", GeneratedMovementTestInput{ @@ -1955,7 +1975,7 @@ static constexpr std::array s_movementTests{ 0, midDocEndLeft, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 4 5 times by Line", GeneratedMovementTestInput{ @@ -1967,7 +1987,7 @@ static constexpr std::array s_movementTests{ 0, midDocEndLeft, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 4 -5 times by Document", GeneratedMovementTestInput{ @@ -1979,7 +1999,7 @@ static constexpr std::array s_movementTests{ -1, origin, origin }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 4 -1 times by Document", GeneratedMovementTestInput{ @@ -1991,7 +2011,7 @@ static constexpr std::array s_movementTests{ -1, origin, origin }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 4 0 times by Document", GeneratedMovementTestInput{ @@ -2003,7 +2023,7 @@ static constexpr std::array s_movementTests{ 0, midDocEnd, midDocEnd }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 4 1 times by Document", GeneratedMovementTestInput{ @@ -2015,7 +2035,7 @@ static constexpr std::array s_movementTests{ 1, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 4 5 times by Document", GeneratedMovementTestInput{ @@ -2027,7 +2047,7 @@ static constexpr std::array s_movementTests{ 1, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 4 -5 times by Document", GeneratedMovementTestInput{ @@ -2039,7 +2059,7 @@ static constexpr std::array s_movementTests{ 0, origin, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 4 -1 times by Document", GeneratedMovementTestInput{ @@ -2051,7 +2071,7 @@ static constexpr std::array s_movementTests{ 0, origin, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 4 0 times by Document", GeneratedMovementTestInput{ @@ -2063,7 +2083,7 @@ static constexpr std::array s_movementTests{ 0, origin, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 4 1 times by Document", GeneratedMovementTestInput{ @@ -2075,7 +2095,7 @@ static constexpr std::array s_movementTests{ 0, origin, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 4 5 times by Document", GeneratedMovementTestInput{ @@ -2087,7 +2107,7 @@ static constexpr std::array s_movementTests{ 0, origin, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 5 -5 times by Character", GeneratedMovementTestInput{ @@ -2099,7 +2119,7 @@ static constexpr std::array s_movementTests{ -5, lastCharPosM5C, lastCharPosM5C }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 5 -1 times by Character", GeneratedMovementTestInput{ @@ -2111,7 +2131,7 @@ static constexpr std::array s_movementTests{ -1, lastCharPosM1C, lastCharPosM1C }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 5 0 times by Character", GeneratedMovementTestInput{ @@ -2123,7 +2143,7 @@ static constexpr std::array s_movementTests{ 0, lastCharPos, lastCharPos }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 5 1 times by Character", GeneratedMovementTestInput{ @@ -2133,9 +2153,9 @@ static constexpr std::array s_movementTests{ lastCharPos }, GeneratedMovementTestExpected{ 1, - docEnd, - docEnd }, - true }, + lastCharPosP1C, + lastCharPosP1C }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 5 5 times by Character", GeneratedMovementTestInput{ @@ -2144,10 +2164,10 @@ static constexpr std::array s_movementTests{ lastCharPos, lastCharPos }, GeneratedMovementTestExpected{ - 1, - docEnd, - docEnd }, - true }, + 5, + lastCharPosP5C, + lastCharPosP5C }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 5 -5 times by Character", GeneratedMovementTestInput{ @@ -2159,7 +2179,7 @@ static constexpr std::array s_movementTests{ -5, lastCharPosM5C, lastCharPosM4C }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 5 -1 times by Character", GeneratedMovementTestInput{ @@ -2171,7 +2191,7 @@ static constexpr std::array s_movementTests{ -1, lastCharPosM1C, lastCharPos }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 5 0 times by Character", GeneratedMovementTestInput{ @@ -2182,8 +2202,8 @@ static constexpr std::array s_movementTests{ GeneratedMovementTestExpected{ 0, lastCharPos, - docEnd }, - true }, + lastCharPosP1C }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 5 1 times by Character", GeneratedMovementTestInput{ @@ -2192,10 +2212,10 @@ static constexpr std::array s_movementTests{ lastCharPos, lastCharPosP1C }, GeneratedMovementTestExpected{ - 0, - lastCharPos, - docEnd }, - true }, + 1, + lastCharPosP1C, + lastCharPosP2C }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 5 5 times by Character", GeneratedMovementTestInput{ @@ -2204,10 +2224,10 @@ static constexpr std::array s_movementTests{ lastCharPos, lastCharPosP1C }, GeneratedMovementTestExpected{ - 0, - lastCharPos, - docEnd }, - true }, + 5, + lastCharPosP5C, + lastCharPosP6C }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 5 -5 times by Line", GeneratedMovementTestInput{ @@ -2219,7 +2239,7 @@ static constexpr std::array s_movementTests{ -5, lastCharPosM4L, lastCharPosM4L }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 5 -1 times by Line", GeneratedMovementTestInput{ @@ -2231,7 +2251,7 @@ static constexpr std::array s_movementTests{ -1, lastCharPosLeft, lastCharPosLeft }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 5 0 times by Line", GeneratedMovementTestInput{ @@ -2243,7 +2263,7 @@ static constexpr std::array s_movementTests{ 0, lastCharPos, lastCharPos }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 5 1 times by Line", GeneratedMovementTestInput{ @@ -2255,7 +2275,7 @@ static constexpr std::array s_movementTests{ 1, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 5 5 times by Line", GeneratedMovementTestInput{ @@ -2267,7 +2287,7 @@ static constexpr std::array s_movementTests{ 1, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 5 -5 times by Line", GeneratedMovementTestInput{ @@ -2279,7 +2299,7 @@ static constexpr std::array s_movementTests{ -5, lastCharPosM5L, lastCharPosM4L }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 5 -1 times by Line", GeneratedMovementTestInput{ @@ -2291,7 +2311,7 @@ static constexpr std::array s_movementTests{ -1, lastCharPosM1L, lastCharPosLeft }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 5 0 times by Line", GeneratedMovementTestInput{ @@ -2303,7 +2323,7 @@ static constexpr std::array s_movementTests{ 0, lastCharPosLeft, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 5 1 times by Line", GeneratedMovementTestInput{ @@ -2315,7 +2335,7 @@ static constexpr std::array s_movementTests{ 0, lastCharPosLeft, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 5 5 times by Line", GeneratedMovementTestInput{ @@ -2327,7 +2347,7 @@ static constexpr std::array s_movementTests{ 0, lastCharPosLeft, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 5 -5 times by Document", GeneratedMovementTestInput{ @@ -2339,7 +2359,7 @@ static constexpr std::array s_movementTests{ -1, origin, origin }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 5 -1 times by Document", GeneratedMovementTestInput{ @@ -2351,7 +2371,7 @@ static constexpr std::array s_movementTests{ -1, origin, origin }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 5 0 times by Document", GeneratedMovementTestInput{ @@ -2363,7 +2383,7 @@ static constexpr std::array s_movementTests{ 0, lastCharPos, lastCharPos }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 5 1 times by Document", GeneratedMovementTestInput{ @@ -2375,7 +2395,7 @@ static constexpr std::array s_movementTests{ 1, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 5 5 times by Document", GeneratedMovementTestInput{ @@ -2387,7 +2407,7 @@ static constexpr std::array s_movementTests{ 1, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 5 -5 times by Document", GeneratedMovementTestInput{ @@ -2399,7 +2419,7 @@ static constexpr std::array s_movementTests{ 0, origin, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 5 -1 times by Document", GeneratedMovementTestInput{ @@ -2411,7 +2431,7 @@ static constexpr std::array s_movementTests{ 0, origin, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 5 0 times by Document", GeneratedMovementTestInput{ @@ -2423,7 +2443,7 @@ static constexpr std::array s_movementTests{ 0, origin, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 5 1 times by Document", GeneratedMovementTestInput{ @@ -2435,7 +2455,7 @@ static constexpr std::array s_movementTests{ 0, origin, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 5 5 times by Document", GeneratedMovementTestInput{ @@ -2447,7 +2467,7 @@ static constexpr std::array s_movementTests{ 0, origin, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 6 -5 times by Character", GeneratedMovementTestInput{ @@ -2459,7 +2479,7 @@ static constexpr std::array s_movementTests{ -5, docEndM5C, docEndM5C }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 6 -1 times by Character", GeneratedMovementTestInput{ @@ -2471,7 +2491,7 @@ static constexpr std::array s_movementTests{ -1, docEndM1C, docEndM1C }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 6 0 times by Character", GeneratedMovementTestInput{ @@ -2483,7 +2503,7 @@ static constexpr std::array s_movementTests{ 0, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 6 1 times by Character", GeneratedMovementTestInput{ @@ -2495,7 +2515,7 @@ static constexpr std::array s_movementTests{ 0, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 6 5 times by Character", GeneratedMovementTestInput{ @@ -2507,7 +2527,7 @@ static constexpr std::array s_movementTests{ 0, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 6 -5 times by Character", GeneratedMovementTestInput{ @@ -2519,7 +2539,7 @@ static constexpr std::array s_movementTests{ -5, docEndM5C, docEndM5C }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 6 -1 times by Character", GeneratedMovementTestInput{ @@ -2531,7 +2551,7 @@ static constexpr std::array s_movementTests{ -1, docEndM1C, docEndM1C }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 6 0 times by Character", GeneratedMovementTestInput{ @@ -2543,7 +2563,7 @@ static constexpr std::array s_movementTests{ 0, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 6 1 times by Character", GeneratedMovementTestInput{ @@ -2555,7 +2575,7 @@ static constexpr std::array s_movementTests{ 0, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 6 5 times by Character", GeneratedMovementTestInput{ @@ -2567,7 +2587,7 @@ static constexpr std::array s_movementTests{ 0, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 6 -5 times by Line", GeneratedMovementTestInput{ @@ -2577,9 +2597,9 @@ static constexpr std::array s_movementTests{ docEnd }, GeneratedMovementTestExpected{ -5, - docEndM4L, - docEndM4L }, - true }, + docEndM5L, + docEndM5L }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 6 -1 times by Line", GeneratedMovementTestInput{ @@ -2589,9 +2609,9 @@ static constexpr std::array s_movementTests{ docEnd }, GeneratedMovementTestExpected{ -1, - docEndLeft, - docEndLeft }, - true }, + docEndM1L, + docEndM1L }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 6 0 times by Line", GeneratedMovementTestInput{ @@ -2603,7 +2623,7 @@ static constexpr std::array s_movementTests{ 0, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 6 1 times by Line", GeneratedMovementTestInput{ @@ -2615,7 +2635,7 @@ static constexpr std::array s_movementTests{ 0, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 6 5 times by Line", GeneratedMovementTestInput{ @@ -2627,7 +2647,7 @@ static constexpr std::array s_movementTests{ 0, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 6 -5 times by Line", GeneratedMovementTestInput{ @@ -2637,9 +2657,9 @@ static constexpr std::array s_movementTests{ docEndP1C }, GeneratedMovementTestExpected{ -5, - docEndM4L, - docEndM4L }, - true }, + docEndM5L, + docEndM5L }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 6 -1 times by Line", GeneratedMovementTestInput{ @@ -2649,9 +2669,9 @@ static constexpr std::array s_movementTests{ docEndP1C }, GeneratedMovementTestExpected{ -1, - docEndLeft, - docEndLeft }, - true }, + docEndM1L, + docEndM1L }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 6 0 times by Line", GeneratedMovementTestInput{ @@ -2663,7 +2683,7 @@ static constexpr std::array s_movementTests{ 0, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 6 1 times by Line", GeneratedMovementTestInput{ @@ -2675,7 +2695,7 @@ static constexpr std::array s_movementTests{ 0, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 6 5 times by Line", GeneratedMovementTestInput{ @@ -2687,7 +2707,7 @@ static constexpr std::array s_movementTests{ 0, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 6 -5 times by Document", GeneratedMovementTestInput{ @@ -2699,7 +2719,7 @@ static constexpr std::array s_movementTests{ -1, origin, origin }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 6 -1 times by Document", GeneratedMovementTestInput{ @@ -2711,7 +2731,7 @@ static constexpr std::array s_movementTests{ -1, origin, origin }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 6 0 times by Document", GeneratedMovementTestInput{ @@ -2723,7 +2743,7 @@ static constexpr std::array s_movementTests{ 0, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 6 1 times by Document", GeneratedMovementTestInput{ @@ -2735,7 +2755,7 @@ static constexpr std::array s_movementTests{ 0, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 6 5 times by Document", GeneratedMovementTestInput{ @@ -2747,7 +2767,7 @@ static constexpr std::array s_movementTests{ 0, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 6 -5 times by Document", GeneratedMovementTestInput{ @@ -2759,7 +2779,7 @@ static constexpr std::array s_movementTests{ -1, origin, origin }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 6 -1 times by Document", GeneratedMovementTestInput{ @@ -2771,7 +2791,7 @@ static constexpr std::array s_movementTests{ -1, origin, origin }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 6 0 times by Document", GeneratedMovementTestInput{ @@ -2783,7 +2803,7 @@ static constexpr std::array s_movementTests{ 0, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 6 1 times by Document", GeneratedMovementTestInput{ @@ -2795,7 +2815,7 @@ static constexpr std::array s_movementTests{ 0, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 6 5 times by Document", GeneratedMovementTestInput{ @@ -2807,7 +2827,7 @@ static constexpr std::array s_movementTests{ 0, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 7 -5 times by Character", GeneratedMovementTestInput{ @@ -2819,7 +2839,7 @@ static constexpr std::array s_movementTests{ -5, docEndM5C, docEndM5C }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 7 -1 times by Character", GeneratedMovementTestInput{ @@ -2831,7 +2851,7 @@ static constexpr std::array s_movementTests{ -1, docEndM1C, docEndM1C }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 7 0 times by Character", GeneratedMovementTestInput{ @@ -2843,7 +2863,7 @@ static constexpr std::array s_movementTests{ 0, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 7 1 times by Character", GeneratedMovementTestInput{ @@ -2855,7 +2875,7 @@ static constexpr std::array s_movementTests{ 0, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 7 5 times by Character", GeneratedMovementTestInput{ @@ -2867,7 +2887,7 @@ static constexpr std::array s_movementTests{ 0, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 7 -5 times by Character", GeneratedMovementTestInput{ @@ -2879,7 +2899,7 @@ static constexpr std::array s_movementTests{ -5, docEndM5C, docEndM5C }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 7 -1 times by Character", GeneratedMovementTestInput{ @@ -2891,7 +2911,7 @@ static constexpr std::array s_movementTests{ -1, docEndM1C, docEndM1C }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 7 0 times by Character", GeneratedMovementTestInput{ @@ -2903,7 +2923,7 @@ static constexpr std::array s_movementTests{ 0, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 7 1 times by Character", GeneratedMovementTestInput{ @@ -2915,7 +2935,7 @@ static constexpr std::array s_movementTests{ 0, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 7 5 times by Character", GeneratedMovementTestInput{ @@ -2927,7 +2947,7 @@ static constexpr std::array s_movementTests{ 0, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 7 -5 times by Line", GeneratedMovementTestInput{ @@ -2937,9 +2957,9 @@ static constexpr std::array s_movementTests{ midEmptySpace }, GeneratedMovementTestExpected{ -5, - docEndM4L, - docEndM4L }, - true }, + docEndM5L, + docEndM5L }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 7 -1 times by Line", GeneratedMovementTestInput{ @@ -2949,9 +2969,9 @@ static constexpr std::array s_movementTests{ midEmptySpace }, GeneratedMovementTestExpected{ -1, - docEndLeft, - docEndLeft }, - true }, + docEndM1L, + docEndM1L }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 7 0 times by Line", GeneratedMovementTestInput{ @@ -2963,7 +2983,7 @@ static constexpr std::array s_movementTests{ 0, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 7 1 times by Line", GeneratedMovementTestInput{ @@ -2975,7 +2995,7 @@ static constexpr std::array s_movementTests{ 0, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 7 5 times by Line", GeneratedMovementTestInput{ @@ -2987,7 +3007,7 @@ static constexpr std::array s_movementTests{ 0, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 7 -5 times by Line", GeneratedMovementTestInput{ @@ -2997,9 +3017,9 @@ static constexpr std::array s_movementTests{ midEmptySpaceP1C }, GeneratedMovementTestExpected{ -5, - docEndM4L, - docEndM4L }, - true }, + docEndM5L, + docEndM5L }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 7 -1 times by Line", GeneratedMovementTestInput{ @@ -3009,9 +3029,9 @@ static constexpr std::array s_movementTests{ midEmptySpaceP1C }, GeneratedMovementTestExpected{ -1, - docEndLeft, - docEndLeft }, - true }, + docEndM1L, + docEndM1L }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 7 0 times by Line", GeneratedMovementTestInput{ @@ -3023,7 +3043,7 @@ static constexpr std::array s_movementTests{ 0, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 7 1 times by Line", GeneratedMovementTestInput{ @@ -3035,7 +3055,7 @@ static constexpr std::array s_movementTests{ 0, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 7 5 times by Line", GeneratedMovementTestInput{ @@ -3047,7 +3067,7 @@ static constexpr std::array s_movementTests{ 0, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 7 -5 times by Document", GeneratedMovementTestInput{ @@ -3059,7 +3079,7 @@ static constexpr std::array s_movementTests{ -1, origin, origin }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 7 -1 times by Document", GeneratedMovementTestInput{ @@ -3071,7 +3091,7 @@ static constexpr std::array s_movementTests{ -1, origin, origin }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 7 0 times by Document", GeneratedMovementTestInput{ @@ -3083,7 +3103,7 @@ static constexpr std::array s_movementTests{ 0, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 7 1 times by Document", GeneratedMovementTestInput{ @@ -3095,7 +3115,7 @@ static constexpr std::array s_movementTests{ 0, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move degenerate range at position 7 5 times by Document", GeneratedMovementTestInput{ @@ -3107,7 +3127,7 @@ static constexpr std::array s_movementTests{ 0, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 7 -5 times by Document", GeneratedMovementTestInput{ @@ -3119,7 +3139,7 @@ static constexpr std::array s_movementTests{ -1, origin, origin }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 7 -1 times by Document", GeneratedMovementTestInput{ @@ -3131,7 +3151,7 @@ static constexpr std::array s_movementTests{ -1, origin, origin }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 7 0 times by Document", GeneratedMovementTestInput{ @@ -3143,7 +3163,7 @@ static constexpr std::array s_movementTests{ 0, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 7 1 times by Document", GeneratedMovementTestInput{ @@ -3155,7 +3175,7 @@ static constexpr std::array s_movementTests{ 0, docEnd, docEnd }, - true }, + false }, GeneratedMovementTest{ L"Move non-degenerate range at position 7 5 times by Document", GeneratedMovementTestInput{ @@ -3167,5 +3187,1025 @@ static constexpr std::array s_movementTests{ 0, docEnd, docEnd }, + false }, + GeneratedMovementTest{ + L"Move degenerate range at position 1 -5 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + -5, + origin, + origin }, + GeneratedMovementTestExpected{ + 0, + origin, + origin }, + false }, + GeneratedMovementTest{ + L"Move degenerate range at position 1 -1 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + -1, + origin, + origin }, + GeneratedMovementTestExpected{ + 0, + origin, + origin }, + false }, + GeneratedMovementTest{ + L"Move degenerate range at position 1 0 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 0, + origin, + origin }, + GeneratedMovementTestExpected{ + 0, + origin, + origin }, + false }, + GeneratedMovementTest{ + L"Move degenerate range at position 1 1 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 1, + origin, + origin }, + GeneratedMovementTestExpected{ + 1, + segment1LmidTop, + segment1LmidTop }, + false }, + GeneratedMovementTest{ + L"Move degenerate range at position 1 5 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 5, + origin, + origin }, + GeneratedMovementTestExpected{ + 5, + segment0LmidTopP1L, + segment0LmidTopP1L }, + false }, + GeneratedMovementTest{ + L"Move non-degenerate range at position 1 -5 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + -5, + origin, + originP1C }, + GeneratedMovementTestExpected{ + 0, + origin, + segment1LmidTop }, + false }, + GeneratedMovementTest{ + L"Move non-degenerate range at position 1 -1 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + -1, + origin, + originP1C }, + GeneratedMovementTestExpected{ + 0, + origin, + segment1LmidTop }, + false }, + GeneratedMovementTest{ + L"Move non-degenerate range at position 1 0 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 0, + origin, + originP1C }, + GeneratedMovementTestExpected{ + 0, + origin, + segment1LmidTop }, + false }, + GeneratedMovementTest{ + L"Move non-degenerate range at position 1 1 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 1, + origin, + originP1C }, + GeneratedMovementTestExpected{ + 1, + segment1LmidTop, + segment2LmidTop }, + false }, + GeneratedMovementTest{ + L"Move non-degenerate range at position 1 5 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 5, + origin, + originP1C }, + GeneratedMovementTestExpected{ + 5, + segment0LmidTopP1L, + segment1LmidTopP1L }, + false }, + GeneratedMovementTest{ + L"Move degenerate range at position 2 -5 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + -5, + midTop, + midTop }, + GeneratedMovementTestExpected{ + -3, + origin, + origin }, true }, + GeneratedMovementTest{ + L"Move degenerate range at position 2 -1 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + -1, + midTop, + midTop }, + GeneratedMovementTestExpected{ + -1, + segment2LmidTop, + segment2LmidTop }, + true }, + GeneratedMovementTest{ + L"Move degenerate range at position 2 0 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 0, + midTop, + midTop }, + GeneratedMovementTestExpected{ + 0, + midTop, + midTop }, + false }, + GeneratedMovementTest{ + L"Move degenerate range at position 2 1 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 1, + midTop, + midTop }, + GeneratedMovementTestExpected{ + 1, + segment3LmidTop, + segment3LmidTop }, + false }, + GeneratedMovementTest{ + L"Move degenerate range at position 2 5 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 5, + midTop, + midTop }, + GeneratedMovementTestExpected{ + 5, + segment2LmidTopP1L, + segment2LmidTopP1L }, + false }, + GeneratedMovementTest{ + L"Move non-degenerate range at position 2 -5 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + -5, + midTop, + midTopP1C }, + GeneratedMovementTestExpected{ + -2, + origin, + segment1LmidTop }, + false }, + GeneratedMovementTest{ + L"Move non-degenerate range at position 2 -1 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + -1, + midTop, + midTopP1C }, + GeneratedMovementTestExpected{ + -1, + segment1LmidTop, + segment2LmidTop }, + false }, + GeneratedMovementTest{ + L"Move non-degenerate range at position 2 0 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 0, + midTop, + midTopP1C }, + GeneratedMovementTestExpected{ + 0, + segment2LmidTop, + segment3LmidTop }, + false }, + GeneratedMovementTest{ + L"Move non-degenerate range at position 2 1 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 1, + midTop, + midTopP1C }, + GeneratedMovementTestExpected{ + 1, + segment3LmidTop, + segment4LmidTop }, + false }, + GeneratedMovementTest{ + L"Move non-degenerate range at position 2 5 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 5, + midTop, + midTopP1C }, + GeneratedMovementTestExpected{ + 5, + segment2LmidTopP1L, + segment3LmidTopP1L }, + false }, + GeneratedMovementTest{ + L"Move degenerate range at position 3 -5 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + -5, + midHistory, + midHistory }, + GeneratedMovementTestExpected{ + -5, + segment3LmidHistoryM1L, + segment3LmidHistoryM1L }, + true }, + GeneratedMovementTest{ + L"Move degenerate range at position 3 -1 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + -1, + midHistory, + midHistory }, + GeneratedMovementTestExpected{ + -1, + segment2LmidHistory, + segment2LmidHistory }, + true }, + GeneratedMovementTest{ + L"Move degenerate range at position 3 0 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 0, + midHistory, + midHistory }, + GeneratedMovementTestExpected{ + 0, + midHistory, + midHistory }, + false }, + GeneratedMovementTest{ + L"Move degenerate range at position 3 1 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 1, + midHistory, + midHistory }, + GeneratedMovementTestExpected{ + 1, + segment3LmidHistory, + segment3LmidHistory }, + false }, + GeneratedMovementTest{ + L"Move degenerate range at position 3 5 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 5, + midHistory, + midHistory }, + GeneratedMovementTestExpected{ + 5, + segment2LmidHistoryP1L, + segment2LmidHistoryP1L }, + false }, + GeneratedMovementTest{ + L"Move non-degenerate range at position 3 -5 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + -5, + midHistory, + midHistoryP1C }, + GeneratedMovementTestExpected{ + -5, + segment3LmidHistoryM1L, + segment4LmidHistoryM1L }, + true }, + GeneratedMovementTest{ + L"Move non-degenerate range at position 3 -1 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + -1, + midHistory, + midHistoryP1C }, + GeneratedMovementTestExpected{ + -1, + segment1LmidHistory, + segment2LmidHistory }, + false }, + GeneratedMovementTest{ + L"Move non-degenerate range at position 3 0 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 0, + midHistory, + midHistoryP1C }, + GeneratedMovementTestExpected{ + 0, + segment2LmidHistory, + segment3LmidHistory }, + false }, + GeneratedMovementTest{ + L"Move non-degenerate range at position 3 1 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 1, + midHistory, + midHistoryP1C }, + GeneratedMovementTestExpected{ + 1, + segment3LmidHistory, + segment4LmidHistory }, + false }, + GeneratedMovementTest{ + L"Move non-degenerate range at position 3 5 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 5, + midHistory, + midHistoryP1C }, + GeneratedMovementTestExpected{ + 5, + segment2LmidHistoryP1L, + segment3LmidHistoryP1L }, + false }, + GeneratedMovementTest{ + L"Move degenerate range at position 4 -5 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + -5, + midDocEnd, + midDocEnd }, + GeneratedMovementTestExpected{ + -5, + segment3LmidDocEndM1L, + segment3LmidDocEndM1L }, + true }, + GeneratedMovementTest{ + L"Move degenerate range at position 4 -1 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + -1, + midDocEnd, + midDocEnd }, + GeneratedMovementTestExpected{ + -1, + segment2LmidDocEnd, + segment2LmidDocEnd }, + true }, + GeneratedMovementTest{ + L"Move degenerate range at position 4 0 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 0, + midDocEnd, + midDocEnd }, + GeneratedMovementTestExpected{ + 0, + midDocEnd, + midDocEnd }, + false }, + GeneratedMovementTest{ + L"Move degenerate range at position 4 1 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 1, + midDocEnd, + midDocEnd }, + GeneratedMovementTestExpected{ + 1, + segment3LmidDocEnd, + segment3LmidDocEnd }, + false }, + GeneratedMovementTest{ + L"Move degenerate range at position 4 5 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 5, + midDocEnd, + midDocEnd }, + GeneratedMovementTestExpected{ + 3, + docEnd, + docEnd }, + false }, + GeneratedMovementTest{ + L"Move non-degenerate range at position 4 -5 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + -5, + midDocEnd, + midDocEndP1C }, + GeneratedMovementTestExpected{ + -5, + segment3LmidDocEndM1L, + segment4LmidDocEndM1L }, + true }, + GeneratedMovementTest{ + L"Move non-degenerate range at position 4 -1 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + -1, + midDocEnd, + midDocEndP1C }, + GeneratedMovementTestExpected{ + -1, + segment1LmidDocEnd, + segment2LmidDocEnd }, + false }, + GeneratedMovementTest{ + L"Move non-degenerate range at position 4 0 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 0, + midDocEnd, + midDocEndP1C }, + GeneratedMovementTestExpected{ + 0, + segment2LmidDocEnd, + segment3LmidDocEnd }, + false }, + GeneratedMovementTest{ + L"Move non-degenerate range at position 4 1 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 1, + midDocEnd, + midDocEndP1C }, + GeneratedMovementTestExpected{ + 1, + segment3LmidDocEnd, + segment4LmidDocEnd }, + false }, + GeneratedMovementTest{ + L"Move non-degenerate range at position 4 5 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 5, + midDocEnd, + midDocEndP1C }, + GeneratedMovementTestExpected{ + 2, + segment4LmidDocEnd, + docEnd }, + false }, + GeneratedMovementTest{ + L"Move degenerate range at position 5 -5 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + -5, + lastCharPos, + lastCharPos }, + GeneratedMovementTestExpected{ + -5, + lastCharPosLeft, + lastCharPosLeft }, + true }, + GeneratedMovementTest{ + L"Move degenerate range at position 5 -1 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + -1, + lastCharPos, + lastCharPos }, + GeneratedMovementTestExpected{ + -1, + segment4LmidDocEnd, + segment4LmidDocEnd }, + true }, + GeneratedMovementTest{ + L"Move degenerate range at position 5 0 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 0, + lastCharPos, + lastCharPos }, + GeneratedMovementTestExpected{ + 0, + lastCharPos, + lastCharPos }, + false }, + GeneratedMovementTest{ + L"Move degenerate range at position 5 1 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 1, + lastCharPos, + lastCharPos }, + GeneratedMovementTestExpected{ + 1, + docEnd, + docEnd }, + false }, + GeneratedMovementTest{ + L"Move degenerate range at position 5 5 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 5, + lastCharPos, + lastCharPos }, + GeneratedMovementTestExpected{ + 1, + docEnd, + docEnd }, + false }, + GeneratedMovementTest{ + L"Move non-degenerate range at position 5 -5 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + -5, + lastCharPos, + lastCharPosP1C }, + GeneratedMovementTestExpected{ + -5, + segment4LlastCharPosM1L, + lastCharPosLeft }, + false }, + GeneratedMovementTest{ + L"Move non-degenerate range at position 5 -1 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + -1, + lastCharPos, + lastCharPosP1C }, + GeneratedMovementTestExpected{ + -1, + segment3LmidDocEnd, + segment4LmidDocEnd }, + false }, + GeneratedMovementTest{ + L"Move non-degenerate range at position 5 0 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 0, + lastCharPos, + lastCharPosP1C }, + GeneratedMovementTestExpected{ + 0, + segment4LmidDocEnd, + docEnd }, + false }, + GeneratedMovementTest{ + L"Move non-degenerate range at position 5 1 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 1, + lastCharPos, + lastCharPosP1C }, + GeneratedMovementTestExpected{ + 0, + segment4LmidDocEnd, + docEnd }, + false }, + GeneratedMovementTest{ + L"Move non-degenerate range at position 5 5 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 5, + lastCharPos, + lastCharPosP1C }, + GeneratedMovementTestExpected{ + 0, + segment4LmidDocEnd, + docEnd }, + false }, + GeneratedMovementTest{ + L"Move degenerate range at position 6 -5 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + -5, + docEnd, + docEnd }, + GeneratedMovementTestExpected{ + -5, + midDocEndLeft, + midDocEndLeft }, + true }, + GeneratedMovementTest{ + L"Move degenerate range at position 6 -1 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + -1, + docEnd, + docEnd }, + GeneratedMovementTestExpected{ + -1, + segment4LmidDocEnd, + segment4LmidDocEnd }, + true }, + GeneratedMovementTest{ + L"Move degenerate range at position 6 0 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 0, + docEnd, + docEnd }, + GeneratedMovementTestExpected{ + 0, + docEnd, + docEnd }, + false }, + GeneratedMovementTest{ + L"Move degenerate range at position 6 1 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 1, + docEnd, + docEnd }, + GeneratedMovementTestExpected{ + 0, + docEnd, + docEnd }, + false }, + GeneratedMovementTest{ + L"Move degenerate range at position 6 5 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 5, + docEnd, + docEnd }, + GeneratedMovementTestExpected{ + 0, + docEnd, + docEnd }, + false }, + GeneratedMovementTest{ + L"Move non-degenerate range at position 6 -5 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + -5, + docEnd, + docEndP1C }, + GeneratedMovementTestExpected{ + -5, + midDocEndLeft, + midDocEndLeft }, + true }, + GeneratedMovementTest{ + L"Move non-degenerate range at position 6 -1 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + -1, + docEnd, + docEndP1C }, + GeneratedMovementTestExpected{ + -1, + segment4LmidDocEnd, + segment4LmidDocEnd }, + true }, + GeneratedMovementTest{ + L"Move non-degenerate range at position 6 0 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 0, + docEnd, + docEndP1C }, + GeneratedMovementTestExpected{ + 0, + docEnd, + docEnd }, + false }, + GeneratedMovementTest{ + L"Move non-degenerate range at position 6 1 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 1, + docEnd, + docEndP1C }, + GeneratedMovementTestExpected{ + 0, + docEnd, + docEnd }, + false }, + GeneratedMovementTest{ + L"Move non-degenerate range at position 6 5 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 5, + docEnd, + docEndP1C }, + GeneratedMovementTestExpected{ + 0, + docEnd, + docEnd }, + false }, + GeneratedMovementTest{ + L"Move degenerate range at position 7 -5 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + -5, + midEmptySpace, + midEmptySpace }, + GeneratedMovementTestExpected{ + -5, + midDocEndLeft, + midDocEndLeft }, + true }, + GeneratedMovementTest{ + L"Move degenerate range at position 7 -1 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + -1, + midEmptySpace, + midEmptySpace }, + GeneratedMovementTestExpected{ + -1, + segment4LmidDocEnd, + segment4LmidDocEnd }, + true }, + GeneratedMovementTest{ + L"Move degenerate range at position 7 0 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 0, + midEmptySpace, + midEmptySpace }, + GeneratedMovementTestExpected{ + 0, + docEnd, + docEnd }, + false }, + GeneratedMovementTest{ + L"Move degenerate range at position 7 1 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 1, + midEmptySpace, + midEmptySpace }, + GeneratedMovementTestExpected{ + 0, + docEnd, + docEnd }, + false }, + GeneratedMovementTest{ + L"Move degenerate range at position 7 5 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 5, + midEmptySpace, + midEmptySpace }, + GeneratedMovementTestExpected{ + 0, + docEnd, + docEnd }, + false }, + GeneratedMovementTest{ + L"Move non-degenerate range at position 7 -5 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + -5, + midEmptySpace, + midEmptySpaceP1C }, + GeneratedMovementTestExpected{ + -5, + midDocEndLeft, + midDocEndLeft }, + true }, + GeneratedMovementTest{ + L"Move non-degenerate range at position 7 -1 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + -1, + midEmptySpace, + midEmptySpaceP1C }, + GeneratedMovementTestExpected{ + -1, + segment4LmidDocEnd, + segment4LmidDocEnd }, + true }, + GeneratedMovementTest{ + L"Move non-degenerate range at position 7 0 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 0, + midEmptySpace, + midEmptySpaceP1C }, + GeneratedMovementTestExpected{ + 0, + docEnd, + docEnd }, + false }, + GeneratedMovementTest{ + L"Move non-degenerate range at position 7 1 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 1, + midEmptySpace, + midEmptySpaceP1C }, + GeneratedMovementTestExpected{ + 0, + docEnd, + docEnd }, + false }, + GeneratedMovementTest{ + L"Move non-degenerate range at position 7 5 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 5, + midEmptySpace, + midEmptySpaceP1C }, + GeneratedMovementTestExpected{ + 0, + docEnd, + docEnd }, + false }, + GeneratedMovementTest{ + L"Move degenerate range at position 8 -5 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + -5, + bufferEnd, + bufferEnd }, + GeneratedMovementTestExpected{ + -5, + midDocEndLeft, + midDocEndLeft }, + true }, + GeneratedMovementTest{ + L"Move degenerate range at position 8 -1 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + -1, + bufferEnd, + bufferEnd }, + GeneratedMovementTestExpected{ + -1, + segment4LmidDocEnd, + segment4LmidDocEnd }, + true }, + GeneratedMovementTest{ + L"Move degenerate range at position 8 0 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 0, + bufferEnd, + bufferEnd }, + GeneratedMovementTestExpected{ + 0, + docEnd, + docEnd }, + false }, + GeneratedMovementTest{ + L"Move degenerate range at position 8 1 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 1, + bufferEnd, + bufferEnd }, + GeneratedMovementTestExpected{ + 0, + docEnd, + docEnd }, + false }, + GeneratedMovementTest{ + L"Move degenerate range at position 8 5 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 5, + bufferEnd, + bufferEnd }, + GeneratedMovementTestExpected{ + 0, + docEnd, + docEnd }, + false }, + GeneratedMovementTest{ + L"Move non-degenerate range at position 8 -5 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + -5, + bufferEnd, + endExclusive }, + GeneratedMovementTestExpected{ + -5, + midDocEndLeft, + midDocEndLeft }, + true }, + GeneratedMovementTest{ + L"Move non-degenerate range at position 8 -1 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + -1, + bufferEnd, + endExclusive }, + GeneratedMovementTestExpected{ + -1, + segment4LmidDocEnd, + segment4LmidDocEnd }, + true }, + GeneratedMovementTest{ + L"Move non-degenerate range at position 8 0 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 0, + bufferEnd, + endExclusive }, + GeneratedMovementTestExpected{ + 0, + docEnd, + docEnd }, + false }, + GeneratedMovementTest{ + L"Move non-degenerate range at position 8 1 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 1, + bufferEnd, + endExclusive }, + GeneratedMovementTestExpected{ + 0, + docEnd, + docEnd }, + false }, + GeneratedMovementTest{ + L"Move non-degenerate range at position 8 5 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 5, + bufferEnd, + endExclusive }, + GeneratedMovementTestExpected{ + 0, + docEnd, + docEnd }, + false }, + GeneratedMovementTest{ + L"Move degenerate range at position 9 -5 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + -5, + endExclusive, + endExclusive }, + GeneratedMovementTestExpected{ + -5, + midDocEndLeft, + midDocEndLeft }, + true }, + GeneratedMovementTest{ + L"Move degenerate range at position 9 -1 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + -1, + endExclusive, + endExclusive }, + GeneratedMovementTestExpected{ + -1, + segment4LmidDocEnd, + segment4LmidDocEnd }, + true }, + GeneratedMovementTest{ + L"Move degenerate range at position 9 0 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 0, + endExclusive, + endExclusive }, + GeneratedMovementTestExpected{ + 0, + docEnd, + docEnd }, + false }, + GeneratedMovementTest{ + L"Move degenerate range at position 9 1 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 1, + endExclusive, + endExclusive }, + GeneratedMovementTestExpected{ + 0, + docEnd, + docEnd }, + false }, + GeneratedMovementTest{ + L"Move degenerate range at position 9 5 times by Word", + GeneratedMovementTestInput{ + TextUnit::TextUnit_Word, + 5, + endExclusive, + endExclusive }, + GeneratedMovementTestExpected{ + 0, + docEnd, + docEnd }, + false }, }; diff --git a/src/interactivity/win32/ut_interactivity_win32/UiaTextRangeTests.cpp b/src/interactivity/win32/ut_interactivity_win32/UiaTextRangeTests.cpp index b6a0557e2..816913825 100644 --- a/src/interactivity/win32/ut_interactivity_win32/UiaTextRangeTests.cpp +++ b/src/interactivity/win32/ut_interactivity_win32/UiaTextRangeTests.cpp @@ -349,14 +349,29 @@ class UiaTextRangeTests _pTextBuffer = &_pScreenInfo->GetTextBuffer(); _pUiaData = &gci.renderData; - // fill text buffer with text - for (UINT i = 0; i < _pTextBuffer->TotalRowCount(); ++i) + // GH#6986: document end now limits the navigation to be + // within the document end bounds _as opposed to_ the buffer bounds. + // As a result, let's populate the buffer partially to define a document end. + // Additionally, add spaces to create "words" in the buffer. + + // LOAD BEARING: make sure we fill it halfway so that we can reuse most of + // the variables from the generated tests. + + // fill first half of text buffer with text + for (UINT i = 0; i < _pTextBuffer->TotalRowCount() / 2; ++i) { ROW& row = _pTextBuffer->GetRowByOffset(i); auto& charRow = row.GetCharRow(); for (auto& cell : charRow) { - cell.Char() = L' '; + if (i % 2 == 0) + { + cell.Char() = L' '; + } + else + { + cell.Char() = L'X'; + } } } @@ -719,9 +734,13 @@ class UiaTextRangeTests TEST_METHOD(CanMoveByCharacter) { - const SHORT lastColumnIndex = _pScreenInfo->GetBufferSize().Width() - 1; + const SHORT lastColumnIndex = _pScreenInfo->GetBufferSize().RightInclusive(); const SHORT bottomRow = gsl::narrow(_pTextBuffer->TotalRowCount() - 1); + // GH#6986: This is used as the "end of the buffer" to help screen readers run faster + // instead of parsing through thousands of empty lines of text. + const COORD documentEnd{ _pTextBuffer->GetSize().Left(), _pTextBuffer->GetLastNonSpaceCharacter().Y + 1 }; + // clang-format off const std::vector testData { @@ -749,6 +768,18 @@ class UiaTextRangeTests } }, + MoveTest{ + L"can't move past the end of the 'document'", + documentEnd, + documentEnd, + 5, + { + 0, + documentEnd, + documentEnd, + } + }, + MoveTest{ L"can move to a new row when necessary when moving forward", { lastColumnIndex, 0 }, @@ -782,7 +813,7 @@ class UiaTextRangeTests int amountMoved; THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&utr, _pUiaData, &_dummyProvider, test.start, test.end)); - utr->Move(TextUnit::TextUnit_Character, test.moveAmt, &amountMoved); + THROW_IF_FAILED(utr->Move(TextUnit::TextUnit_Character, test.moveAmt, &amountMoved)); VERIFY_ARE_EQUAL(test.expected.moveAmt, amountMoved); VERIFY_ARE_EQUAL(test.expected.start, utr->_start); @@ -795,6 +826,10 @@ class UiaTextRangeTests const SHORT lastColumnIndex = _pScreenInfo->GetBufferSize().Width() - 1; const SHORT bottomRow = gsl::narrow(_pTextBuffer->TotalRowCount() - 1); + // GH#6986: This is used as the "end of the buffer" to help screen readers run faster + // instead of parsing through thousands of empty lines of text. + const COORD documentEnd{ _pTextBuffer->GetSize().Left(), _pTextBuffer->GetLastNonSpaceCharacter().Y + 1 }; + // clang-format off const std::vector testData { @@ -810,15 +845,27 @@ class UiaTextRangeTests } }, + MoveTest{ + L"can't move past the end of the 'document'", + documentEnd, + documentEnd, + 5, + { + 0, + documentEnd, + documentEnd, + } + }, + MoveTest{ L"can move backward from bottom row", - {0, bottomRow}, - {lastColumnIndex, bottomRow}, + {0, documentEnd.Y}, + {lastColumnIndex, documentEnd.Y}, -3, { -3, - {0, bottomRow - 3}, - {0, bottomRow - 2} + {0, base::ClampSub(documentEnd.Y, 3)}, + {0, base::ClampSub(documentEnd.Y, 3)} } }, @@ -868,6 +915,10 @@ class UiaTextRangeTests const SHORT lastColumnIndex = _pScreenInfo->GetBufferSize().Width() - 1; const SHORT bottomRow = static_cast(_pTextBuffer->TotalRowCount() - 1); + // GH#6986: This is used as the "end of the buffer" to help screen readers run faster + // instead of parsing through thousands of empty lines of text. + const COORD documentEnd{ _pTextBuffer->GetSize().RightInclusive(), _pTextBuffer->GetLastNonSpaceCharacter().Y }; + // clang-format off const std::vector testData { @@ -910,6 +961,19 @@ class UiaTextRangeTests } }, + MoveEndpointTest{ + L"can't move _end past the end of the document", + {0, 0}, + documentEnd, + 5, + TextPatternRangeEndpoint_End, + { + 1, + {0,0}, + {0, base::ClampAdd(documentEnd.Y,1)} + } + }, + MoveEndpointTest{ L"_start follows _end when passed during movement", {5, 0}, @@ -925,40 +989,40 @@ class UiaTextRangeTests MoveEndpointTest{ L"can't move _end past the beginning of the document when _end is positioned at the end", - {0, bottomRow}, - {0, bottomRow+1}, + {0, documentEnd.Y}, + {0, base::ClampAdd(documentEnd.Y,1)}, 1, TextPatternRangeEndpoint_End, { 0, - {0, bottomRow}, - {0, bottomRow+1}, + {0, documentEnd.Y}, + {0, base::ClampAdd(documentEnd.Y,1)}, } }, MoveEndpointTest{ L"can partially move _end to the end of the document when it is closer than the move count requested", {0, 0}, - {lastColumnIndex - 3, bottomRow}, + {base::ClampSub(lastColumnIndex, 3), documentEnd.Y}, 5, TextPatternRangeEndpoint_End, { 4, {0, 0}, - {0, bottomRow+1}, + {0, base::ClampAdd(documentEnd.Y,1)}, } }, MoveEndpointTest{ L"can't move _start past the end of the document", - {lastColumnIndex - 4, bottomRow}, - {0, bottomRow+1}, + {base::ClampSub(lastColumnIndex, 4), documentEnd.Y}, + {0, base::ClampAdd(documentEnd.Y,1)}, 5, TextPatternRangeEndpoint_Start, { 5, - {0, bottomRow+1}, - {0, bottomRow+1}, + {0, base::ClampAdd(documentEnd.Y,1)}, + {0, base::ClampAdd(documentEnd.Y,1)}, } }, @@ -997,6 +1061,10 @@ class UiaTextRangeTests const SHORT lastColumnIndex = _pScreenInfo->GetBufferSize().Width() - 1; const SHORT bottomRow = gsl::narrow(_pTextBuffer->TotalRowCount() - 1); + // GH#6986: This is used as the "end of the buffer" to help screen readers run faster + // instead of parsing through thousands of empty lines of text. + const COORD documentEnd{ _pTextBuffer->GetSize().Left(), _pTextBuffer->GetLastNonSpaceCharacter().Y + 1 }; + // clang-format off const std::vector testData { @@ -1067,36 +1135,36 @@ class UiaTextRangeTests }, MoveEndpointTest{ - L"can move _end forwards when it's on the bottom row", + L"can't move _end forwards when it's on the bottom row (past doc end)", {0, 0}, {lastColumnIndex - 3, bottomRow}, 1, TextPatternRangeEndpoint_End, - 1, + 0, {0, 0}, - {0, bottomRow+1} + documentEnd }, MoveEndpointTest{ - L"can't move _end forwards when it's at the end of the document already", + L"can't move _end forwards when it's at the end of the buffer already (past doc end)", {0, 0}, {0, bottomRow+1}, 1, TextPatternRangeEndpoint_End, 0, {0, 0}, - {0, bottomRow+1} + documentEnd }, MoveEndpointTest{ - L"moving _start forward when it's already on the bottom row creates a degenerate range at the document end", + L"moving _start forward when it's already on the bottom row (past doc end) creates a degenerate range at the document end", {0, bottomRow}, {lastColumnIndex, bottomRow}, 1, TextPatternRangeEndpoint_Start, - 1, - {0, bottomRow+1}, - {0, bottomRow+1} + 0, + documentEnd, + documentEnd }, MoveEndpointTest{ @@ -1132,6 +1200,10 @@ class UiaTextRangeTests const SHORT lastColumnIndex = _pScreenInfo->GetBufferSize().Width() - 1; const SHORT bottomRow = gsl::narrow(_pTextBuffer->TotalRowCount() - 1); + // GH#6986: This is used as the "end of the buffer" to help screen readers run faster + // instead of parsing through thousands of empty lines of text. + const COORD documentEnd{ _pTextBuffer->GetSize().Left(), _pTextBuffer->GetLastNonSpaceCharacter().Y + 1 }; + // clang-format off const std::vector testData = { @@ -1144,7 +1216,7 @@ class UiaTextRangeTests { 1, {0, 4}, - {0, bottomRow+1} + documentEnd } }, @@ -1162,7 +1234,7 @@ class UiaTextRangeTests }, MoveEndpointTest{ - L"can't move _end forward when it's already at the end of the document", + L"can't move _end forward when it's already at the end of the buffer (past doc end)", {3, 2}, {0, bottomRow+1}, 1, @@ -1170,7 +1242,7 @@ class UiaTextRangeTests { 0, {3, 2}, - {0, bottomRow+1} + documentEnd } }, @@ -1208,8 +1280,8 @@ class UiaTextRangeTests TextPatternRangeEndpoint_Start, { 1, - {0, bottomRow+1}, - {0, bottomRow+1} + documentEnd, + documentEnd } } }; @@ -1235,51 +1307,64 @@ class UiaTextRangeTests // GH#7664: When attempting to expand to an enclosing unit // at the end exclusive, the UTR should refuse to move past // the end. + const auto lastNonspaceCharPos{ _pTextBuffer->GetLastNonSpaceCharacter() }; + const COORD documentEnd{ 0, lastNonspaceCharPos.Y + 1 }; - const til::point endInclusive{ bufferEnd }; - - // Iterate over each TextUnit. If the we don't support + // Iterate over each TextUnit. If we don't support // the given TextUnit, we're supposed to fallback // to the last one that was defined anyways. + BEGIN_TEST_METHOD_PROPERTIES() + TEST_METHOD_PROPERTY(L"Data:textUnit", L"{0, 1, 2, 3, 4, 5, 6}") + END_TEST_METHOD_PROPERTIES(); + + int textUnit; + VERIFY_SUCCEEDED(TestData::TryGetValue(L"textUnit", textUnit), L"Get textUnit variant"); + Microsoft::WRL::ComPtr utr; - for (int unit = TextUnit::TextUnit_Character; unit != TextUnit::TextUnit_Document; ++unit) - { - Log::Comment(NoThrowString().Format(L"%s", toString(static_cast(unit)))); + Log::Comment(NoThrowString().Format(L"%s", toString(static_cast(textUnit)))); - // Create a degenerate UTR at EndExclusive - THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&utr, _pUiaData, &_dummyProvider, endInclusive, endExclusive)); - THROW_IF_FAILED(utr->ExpandToEnclosingUnit(static_cast(unit))); + // Create a degenerate UTR at EndExclusive + THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&utr, _pUiaData, &_dummyProvider, bufferEnd, endExclusive)); + THROW_IF_FAILED(utr->ExpandToEnclosingUnit(static_cast(textUnit))); - VERIFY_ARE_EQUAL(endExclusive, til::point{ utr->_end }); - } + VERIFY_ARE_EQUAL(documentEnd, til::point{ utr->_end }); } TEST_METHOD(MovementAtExclusiveEnd) { // GH#7663: When attempting to move from end exclusive, // the UTR should refuse to move past the end. - - const auto lastLineStart{ bufferEndLeft }; - const auto secondToLastLinePos{ point_offset_by_line(lastLineStart, bufferSize, -1) }; - const auto secondToLastCharacterPos{ point_offset_by_char(bufferEnd, bufferSize, -1) }; const auto endInclusive{ bufferEnd }; // write "temp" at (2,2) + _pTextBuffer->Reset(); const til::point writeTarget{ 2, 2 }; _pTextBuffer->Write({ L"temp" }, writeTarget); + // GH#6986: This is used as the "end of the buffer" to help screen readers run faster + // instead of parsing through thousands of empty lines of text. + const COORD documentEndInclusive{ base::ClampSub(static_cast(bufferSize.right()), 1), _pTextBuffer->GetLastNonSpaceCharacter().Y }; + const COORD documentEndExclusive{ static_cast(bufferSize.left()), base::ClampAdd(documentEndInclusive.Y, 1) }; + + const COORD lastLineStart{ static_cast(bufferSize.left()), documentEndInclusive.Y }; + const auto secondToLastLinePos{ point_offset_by_line(lastLineStart, bufferSize, -1) }; + const COORD secondToLastCharacterPos{ documentEndInclusive.X - 1, documentEndInclusive.Y }; + // Iterate over each TextUnit. If we don't support // the given TextUnit, we're supposed to fallback // to the last one that was defined anyways. BEGIN_TEST_METHOD_PROPERTIES() TEST_METHOD_PROPERTY(L"Data:textUnit", L"{0, 1, 2, 3, 4, 5, 6}") TEST_METHOD_PROPERTY(L"Data:degenerate", L"{false, true}") + TEST_METHOD_PROPERTY(L"Data:atDocumentEnd", L"{false, true}") END_TEST_METHOD_PROPERTIES(); int unit; bool degenerate; + bool atDocumentEnd; VERIFY_SUCCEEDED(TestData::TryGetValue(L"textUnit", unit), L"Get TextUnit variant"); VERIFY_SUCCEEDED(TestData::TryGetValue(L"degenerate", degenerate), L"Get degenerate variant"); + VERIFY_SUCCEEDED(TestData::TryGetValue(L"atDocumentEnd", atDocumentEnd), L"Get atDocumentEnd variant"); TextUnit textUnit{ static_cast(unit) }; Microsoft::WRL::ComPtr utr; @@ -1287,17 +1372,22 @@ class UiaTextRangeTests Log::Comment(NoThrowString().Format(L"Forward by %s", toString(textUnit))); // Create an UTR at EndExclusive + const auto utrEnd{ atDocumentEnd ? documentEndExclusive : endExclusive }; if (degenerate) { - THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&utr, _pUiaData, &_dummyProvider, endExclusive, endExclusive)); + // UTR: (exclusive, exclusive) range + const auto utrStart{ atDocumentEnd ? documentEndExclusive : endExclusive }; + THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&utr, _pUiaData, &_dummyProvider, utrStart, utrEnd)); } else { - THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&utr, _pUiaData, &_dummyProvider, endInclusive, endExclusive)); + // UTR: (inclusive, exclusive) range + const auto utrStart{ atDocumentEnd ? documentEndInclusive : endInclusive }; + THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&utr, _pUiaData, &_dummyProvider, utrStart, utrEnd)); } THROW_IF_FAILED(utr->Move(textUnit, 1, &moveAmt)); - VERIFY_ARE_EQUAL(endExclusive, til::point{ utr->_end }); + VERIFY_ARE_EQUAL(documentEndExclusive, utr->_end); VERIFY_ARE_EQUAL(0, moveAmt); // Verify expansion works properly @@ -1305,33 +1395,35 @@ class UiaTextRangeTests THROW_IF_FAILED(utr->ExpandToEnclosingUnit(textUnit)); if (textUnit <= TextUnit::TextUnit_Character) { - VERIFY_ARE_EQUAL(endInclusive, til::point{ utr->_start }); - VERIFY_ARE_EQUAL(endExclusive, til::point{ utr->_end }); + VERIFY_ARE_EQUAL(documentEndInclusive, utr->_start); + VERIFY_ARE_EQUAL(documentEndExclusive, utr->_end); } else if (textUnit <= TextUnit::TextUnit_Word) { VERIFY_ARE_EQUAL(writeTarget, til::point{ utr->_start }); - VERIFY_ARE_EQUAL(endExclusive, til::point{ utr->_end }); + VERIFY_ARE_EQUAL(documentEndExclusive, utr->_end); } else if (textUnit <= TextUnit::TextUnit_Line) { - VERIFY_ARE_EQUAL(lastLineStart, til::point{ utr->_start }); - VERIFY_ARE_EQUAL(endExclusive, til::point{ utr->_end }); + VERIFY_ARE_EQUAL(lastLineStart, utr->_start); + VERIFY_ARE_EQUAL(documentEndExclusive, utr->_end); } else // textUnit <= TextUnit::TextUnit_Document: { VERIFY_ARE_EQUAL(origin, til::point{ utr->_start }); - VERIFY_ARE_EQUAL(endExclusive, til::point{ utr->_end }); + VERIFY_ARE_EQUAL(documentEndExclusive, utr->_end); } // reset the UTR if (degenerate) { - THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&utr, _pUiaData, &_dummyProvider, endExclusive, endExclusive)); + const auto utrStart{ atDocumentEnd ? documentEndExclusive : endExclusive }; + THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&utr, _pUiaData, &_dummyProvider, utrStart, utrEnd)); } else { - THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&utr, _pUiaData, &_dummyProvider, endInclusive, endExclusive)); + const auto utrStart{ atDocumentEnd ? documentEndInclusive : endInclusive }; + THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&utr, _pUiaData, &_dummyProvider, utrStart, utrEnd)); } // Verify that moving backwards still works properly @@ -1345,26 +1437,26 @@ class UiaTextRangeTests // - degenerate --> it moves with _start to stay degenerate // - !degenerate --> it excludes the last char, to select the second to last char VERIFY_ARE_EQUAL(-1, moveAmt); - VERIFY_ARE_EQUAL(degenerate ? endInclusive : secondToLastCharacterPos, til::point{ utr->_start }); - VERIFY_ARE_EQUAL(endInclusive, til::point{ utr->_end }); + VERIFY_ARE_EQUAL(degenerate || !atDocumentEnd ? documentEndInclusive : secondToLastCharacterPos, utr->_start); + VERIFY_ARE_EQUAL(documentEndInclusive, utr->_end); } else if (textUnit <= TextUnit::TextUnit_Word) { VERIFY_ARE_EQUAL(-1, moveAmt); VERIFY_ARE_EQUAL(origin, til::point{ utr->_start }); - VERIFY_ARE_EQUAL(degenerate ? origin : writeTarget, til::point{ utr->_end }); + VERIFY_ARE_EQUAL(degenerate || !atDocumentEnd ? origin : writeTarget, til::point{ utr->_end }); } else if (textUnit <= TextUnit::TextUnit_Line) { VERIFY_ARE_EQUAL(-1, moveAmt); - VERIFY_ARE_EQUAL(degenerate ? lastLineStart : secondToLastLinePos, til::point{ utr->_start }); + VERIFY_ARE_EQUAL(degenerate || !atDocumentEnd ? lastLineStart : secondToLastLinePos, til::point{ utr->_start }); VERIFY_ARE_EQUAL(lastLineStart, til::point{ utr->_end }); } else // textUnit <= TextUnit::TextUnit_Document: { - VERIFY_ARE_EQUAL(degenerate ? -1 : 0, moveAmt); + VERIFY_ARE_EQUAL(degenerate || !atDocumentEnd ? -1 : 0, moveAmt); VERIFY_ARE_EQUAL(origin, til::point{ utr->_start }); - VERIFY_ARE_EQUAL(degenerate ? origin : endExclusive, til::point{ utr->_end }); + VERIFY_ARE_EQUAL(degenerate || !atDocumentEnd ? origin : documentEndExclusive, til::point{ utr->_end }); } } @@ -1829,37 +1921,38 @@ class UiaTextRangeTests TEST_METHOD(GeneratedMovementTests) { // Populate the buffer with... - // - 9 segments of alternating text + // - 10 segments of alternating text // - up to half of the buffer (vertically) // It'll look something like this - // +---------------------------+ - // |XXX XXX XXX XXX XXX| - // |XXX XXX XXX XXX XXX| - // |XXX XXX XXX XXX XXX| - // |XXX XXX XXX XXX XXX| - // |XXX XXX XXX XXX XXX| - // | | - // | | - // | | - // | | - // | | - // +---------------------------+ + // +------------------------------+ + // |XXX XXX XXX XXX XXX | + // |XXX XXX XXX XXX XXX | + // |XXX XXX XXX XXX XXX | + // |XXX XXX XXX XXX XXX | + // |XXX XXX XXX XXX XXX | + // | | + // | | + // | | + // | | + // | | + // +------------------------------+ { short i = 0; auto iter{ _pTextBuffer->GetCellDataAt(bufferSize.origin()) }; - const auto segment{ bufferSize.width() / 9 }; + const auto segment{ bufferSize.width() / 10 }; + bool fill{ true }; while (iter.Pos() != docEnd) { - bool fill{ true }; - if (i % segment == 0) + if (iter.Pos().X == bufferSize.left()) + { + fill = true; + } + else if (i % segment == 0) { fill = !fill; } - if (fill) - { - _pTextBuffer->Write({ L"X" }, iter.Pos()); - } + _pTextBuffer->Write({ fill ? L"X" : L" " }, iter.Pos()); ++i; ++iter; diff --git a/src/types/UiaTextRangeBase.cpp b/src/types/UiaTextRangeBase.cpp index 5c73d06e3..ace7002c2 100644 --- a/src/types/UiaTextRangeBase.cpp +++ b/src/types/UiaTextRangeBase.cpp @@ -280,52 +280,50 @@ IFACEMETHODIMP UiaTextRangeBase::ExpandToEnclosingUnit(_In_ TextUnit unit) noexc void UiaTextRangeBase::_expandToEnclosingUnit(TextUnit unit) { const auto& buffer = _pData->GetTextBuffer(); - const auto bufferSize = _getBufferSize(); - const auto bufferEnd = bufferSize.EndExclusive(); + const auto bufferSize{ buffer.GetSize() }; + const auto documentEnd{ _getDocumentEnd() }; + + // If we're past document end, + // set us to ONE BEFORE the document end. + // This allows us to expand properly. + if (bufferSize.CompareInBounds(_start, documentEnd, true) >= 0) + { + _start = documentEnd; + bufferSize.DecrementInBounds(_start, true); + } if (unit == TextUnit_Character) { - _start = buffer.GetGlyphStart(_start); - _end = buffer.GetGlyphEnd(_start); + _start = buffer.GetGlyphStart(_start, documentEnd); + _end = buffer.GetGlyphEnd(_start, documentEnd); } else if (unit <= TextUnit_Word) { // expand to word - _start = buffer.GetWordStart(_start, _wordDelimiters, true); - _end = buffer.GetWordEnd(_start, _wordDelimiters, true); - - // GetWordEnd may return the actual end of the TextBuffer. - // If so, just set it to this value of bufferEnd - if (!bufferSize.IsInBounds(_end)) - { - _end = bufferEnd; - } + _start = buffer.GetWordStart(_start, _wordDelimiters, true, documentEnd); + _end = buffer.GetWordEnd(_start, _wordDelimiters, true, documentEnd); } else if (unit <= TextUnit_Line) { - if (_start == bufferEnd) + // expand to line + _start.X = 0; + if (_start.Y == documentEnd.y()) { - // Special case: if we are at the bufferEnd, - // move _start back one, instead of _end forward - _start.X = 0; - _start.Y = base::ClampSub(_start.Y, 1); - _end = bufferEnd; + // we're on the last line + _end = documentEnd; + bufferSize.IncrementInBounds(_end, true); } else { - // expand to line - _start.X = 0; _end.X = 0; _end.Y = base::ClampAdd(_start.Y, 1); } } else { - // TODO GH#6986: properly handle "end of buffer" as last character - // instead of last cell // expand to document _start = bufferSize.Origin(); - _end = bufferSize.EndExclusive(); + _end = documentEnd; } } @@ -608,7 +606,7 @@ try *ppRetVal = nullptr; const std::wstring queryText{ text, SysStringLen(text) }; - const auto bufferSize = _getBufferSize(); + const auto bufferSize = _getOptimizedBufferSize(); const auto sensitivity = ignoreCase ? Search::Sensitivity::CaseInsensitive : Search::Sensitivity::CaseSensitive; auto searchDirection = Search::Direction::Forward; @@ -1016,11 +1014,24 @@ try _pData->UnlockConsole(); }); + // We can abstract this movement by moving _start + // GH#7342: check if we're past the documentEnd + // If so, clamp each endpoint to the end of the document. + constexpr auto endpoint = TextPatternRangeEndpoint::TextPatternRangeEndpoint_Start; + const auto bufferSize{ _pData->GetTextBuffer().GetSize() }; + const COORD documentEnd = _getDocumentEnd(); + if (bufferSize.CompareInBounds(_start, documentEnd, true) > 0) + { + _start = documentEnd; + } + if (bufferSize.CompareInBounds(_end, documentEnd, true) > 0) + { + _end = documentEnd; + } + const auto wasDegenerate = IsDegenerate(); if (count != 0) { - // We can abstract this movement by moving _start - constexpr auto endpoint = TextPatternRangeEndpoint::TextPatternRangeEndpoint_Start; const auto preventBoundary = !wasDegenerate; if (unit == TextUnit::TextUnit_Character) { @@ -1028,13 +1039,7 @@ try } else if (unit <= TextUnit::TextUnit_Word) { - // TODO GH#10925: passing in "true" instead of "preventBoundary" - // We still need to go through the process of writing - // tests, finding failing cases, and fixing them. - // For now, just use true because we've been doing that so far. - // The tests at the time of writing don't report any failures - // if we use one over the other. - _moveEndpointByUnitWord(count, endpoint, pRetVal, true); + _moveEndpointByUnitWord(count, endpoint, pRetVal, preventBoundary); } else if (unit <= TextUnit::TextUnit_Line) { @@ -1080,6 +1085,26 @@ IFACEMETHODIMP UiaTextRangeBase::MoveEndpointByUnit(_In_ TextPatternRangeEndpoin _pData->UnlockConsole(); }); + // GH#7342: check if we're past the documentEnd + // If so, clamp each endpoint to the end of the document. + const auto bufferSize{ _pData->GetTextBuffer().GetSize() }; + + auto documentEnd = bufferSize.EndExclusive(); + try + { + documentEnd = _getDocumentEnd(); + } + CATCH_LOG(); + + if (bufferSize.CompareInBounds(_start, documentEnd, true) > 0) + { + _start = documentEnd; + } + if (bufferSize.CompareInBounds(_end, documentEnd, true) > 0) + { + _end = documentEnd; + } + try { if (unit == TextUnit::TextUnit_Character) @@ -1307,7 +1332,7 @@ const unsigned int UiaTextRangeBase::_getViewportHeight(const SMALL_RECT viewpor // - // Return Value: // - A viewport representing the portion of the TextBuffer that has valid text -const Viewport UiaTextRangeBase::_getBufferSize() const noexcept +const Viewport UiaTextRangeBase::_getOptimizedBufferSize() const noexcept { // we need to add 1 to the X/Y of textBufferEnd // because we want the returned viewport to include this COORD @@ -1318,6 +1343,20 @@ const Viewport UiaTextRangeBase::_getBufferSize() const noexcept return Viewport::FromDimensions({ 0, 0 }, width, height); } +// We consider the "document end" to be the line beneath the cursor or +// last legible character (whichever is further down). In the event where +// the last legible character is on the last line of the buffer, +// we use the "end exclusive" position (left-most point on a line one past the end of the buffer). +// NOTE: "end exclusive" is naturally computed using the heuristic above. +const til::point UiaTextRangeBase::_getDocumentEnd() const +{ + const auto optimizedBufferSize{ _getOptimizedBufferSize() }; + const auto& buffer{ _pData->GetTextBuffer() }; + const auto lastCharPos{ buffer.GetLastNonSpaceCharacter(optimizedBufferSize) }; + const auto cursorPos{ buffer.GetCursor().GetPosition() }; + return { optimizedBufferSize.Left(), std::max(lastCharPos.Y, cursorPos.Y) + 1 }; +} + // Routine Description: // - adds the relevant coordinate points from the row to coords. // - it is assumed that startAnchor and endAnchor are within the same row @@ -1388,19 +1427,20 @@ void UiaTextRangeBase::_moveEndpointByUnitCharacter(_In_ const int moveCount, bool success = true; til::point target = GetEndpoint(endpoint); + const auto documentEnd{ _getDocumentEnd() }; while (std::abs(*pAmountMoved) < std::abs(moveCount) && success) { switch (moveDirection) { case MovementDirection::Forward: - success = buffer.MoveToNextGlyph(target, allowBottomExclusive); + success = buffer.MoveToNextGlyph(target, allowBottomExclusive, documentEnd); if (success) { (*pAmountMoved)++; } break; case MovementDirection::Backward: - success = buffer.MoveToPreviousGlyph(target); + success = buffer.MoveToPreviousGlyph(target, documentEnd); if (success) { (*pAmountMoved)--; @@ -1441,10 +1481,9 @@ void UiaTextRangeBase::_moveEndpointByUnitWord(_In_ const int moveCount, const bool allowBottomExclusive = !preventBufferEnd; const MovementDirection moveDirection = (moveCount > 0) ? MovementDirection::Forward : MovementDirection::Backward; const auto& buffer = _pData->GetTextBuffer(); - const auto bufferSize = _getBufferSize(); + const auto bufferSize = buffer.GetSize(); const auto bufferOrigin = bufferSize.Origin(); - const auto bufferEnd = bufferSize.EndExclusive(); - const auto lastCharPos = buffer.GetLastNonSpaceCharacter(bufferSize); + const auto documentEnd = _getDocumentEnd(); auto resultPos = GetEndpoint(endpoint); auto nextPos = resultPos; @@ -1457,18 +1496,18 @@ void UiaTextRangeBase::_moveEndpointByUnitWord(_In_ const int moveCount, { case MovementDirection::Forward: { - if (nextPos == bufferEnd) + if (bufferSize.CompareInBounds(nextPos, documentEnd, true) >= 0) { success = false; } - else if (buffer.MoveToNextWord(nextPos, _wordDelimiters, lastCharPos)) + else if (buffer.MoveToNextWord(nextPos, _wordDelimiters, documentEnd)) { resultPos = nextPos; (*pAmountMoved)++; } else if (allowBottomExclusive) { - resultPos = bufferEnd; + resultPos = documentEnd; (*pAmountMoved)++; } else @@ -1529,10 +1568,18 @@ void UiaTextRangeBase::_moveEndpointByUnitLine(_In_ const int moveCount, const bool allowBottomExclusive = !preventBoundary; const MovementDirection moveDirection = (moveCount > 0) ? MovementDirection::Forward : MovementDirection::Backward; - const auto bufferSize = _getBufferSize(); + const auto bufferSize = _getOptimizedBufferSize(); + + auto documentEnd{ bufferSize.EndExclusive() }; + try + { + documentEnd = _getDocumentEnd(); + } + CATCH_LOG(); bool success = true; auto resultPos = GetEndpoint(endpoint); + while (std::abs(*pAmountMoved) < std::abs(moveCount) && success) { auto nextPos = resultPos; @@ -1540,22 +1587,29 @@ void UiaTextRangeBase::_moveEndpointByUnitLine(_In_ const int moveCount, { case MovementDirection::Forward: { - // can't move past end - if (nextPos.Y >= bufferSize.BottomInclusive()) + if (nextPos.Y >= documentEnd.Y) { - if (preventBoundary || nextPos == bufferSize.EndExclusive()) - { - success = false; - break; - } + // Corner Case: we're past the limit + // Clamp us to the limit + resultPos = documentEnd; + success = false; } - - nextPos.X = bufferSize.RightInclusive(); - success = bufferSize.IncrementInBounds(nextPos, allowBottomExclusive); - if (success) + else if (preventBoundary && nextPos.Y == base::ClampSub(documentEnd.Y, 1)) { - resultPos = nextPos; - (*pAmountMoved)++; + // Corner Case: we're just before the limit + // and we're not allowed onto the exclusive end. + // Fail to move. + success = false; + } + else + { + nextPos.X = bufferSize.RightInclusive(); + success = bufferSize.IncrementInBounds(nextPos, allowBottomExclusive); + if (success) + { + resultPos = nextPos; + (*pAmountMoved)++; + } } break; } @@ -1621,15 +1675,21 @@ void UiaTextRangeBase::_moveEndpointByUnitDocument(_In_ const int moveCount, } const MovementDirection moveDirection = (moveCount > 0) ? MovementDirection::Forward : MovementDirection::Backward; - const auto bufferSize = _getBufferSize(); + const auto bufferSize = _getOptimizedBufferSize(); const auto target = GetEndpoint(endpoint); switch (moveDirection) { case MovementDirection::Forward: { - const auto documentEnd = bufferSize.EndExclusive(); - if (preventBoundary || target == documentEnd) + auto documentEnd{ bufferSize.EndExclusive() }; + try + { + documentEnd = _getDocumentEnd(); + } + CATCH_LOG(); + + if (preventBoundary || bufferSize.CompareInBounds(target, documentEnd, true) >= 0) { return; } diff --git a/src/types/UiaTextRangeBase.hpp b/src/types/UiaTextRangeBase.hpp index 79a36b894..b3a171b98 100644 --- a/src/types/UiaTextRangeBase.hpp +++ b/src/types/UiaTextRangeBase.hpp @@ -149,7 +149,8 @@ namespace Microsoft::Console::Types virtual const COORD _getScreenFontSize() const; const unsigned int _getViewportHeight(const SMALL_RECT viewport) const noexcept; - const Viewport _getBufferSize() const noexcept; + const Viewport _getOptimizedBufferSize() const noexcept; + const til::point _getDocumentEnd() const; void _getBoundingRect(const til::rectangle textRect, _Inout_ std::vector& coords) const; diff --git a/tools/TestTableWriter/GenerateTests.ps1 b/tools/TestTableWriter/GenerateTests.ps1 index c4432de5c..51c2d8019 100644 --- a/tools/TestTableWriter/GenerateTests.ps1 +++ b/tools/TestTableWriter/GenerateTests.ps1 @@ -21,7 +21,6 @@ $result = "// Copyright (c) Microsoft Corporation. // These were generated by tools\TestTableWriter\GenerateTests.ps1 // Read tools\TestTableWriter\README.md for more details" -# TODO: THIS IS PROBABLY WRONG. Bottom/Right are exclusive (I think?) # 1. Define a few helpful variables to make life easier. $result += " // Define a few helpful variables @@ -29,11 +28,16 @@ constexpr til::rectangle bufferSize{ 0, 0, 80, 300 }; constexpr short midX{ 40 }; constexpr short midY{ 150 }; constexpr short midPopulatedY{ 75 }; +constexpr short segment0{ 0 }; +constexpr short segment1{ 16 }; +constexpr short segment2{ 32 }; +constexpr short segment3{ 48 }; +constexpr short segment4{ 64 }; constexpr til::point origin{ 0, 0 }; constexpr til::point midTop{ midX, 0 }; constexpr til::point midHistory{ midX, midPopulatedY }; constexpr til::point midDocEnd{ midX, midY }; -constexpr til::point lastCharPos{ 79, midY }; +constexpr til::point lastCharPos{ 72, midY }; constexpr til::point docEnd{ 0, midY + 1 }; constexpr til::point midEmptySpace{ midX, midY + midPopulatedY }; constexpr til::point bufferEnd{ 79, 299 }; @@ -55,17 +59,33 @@ foreach ($test in $tests) $vars.Remove("origin") > $null; $vars.Remove("midTop") > $null; $vars.Remove("midHistory") > $null; +$vars.Remove("midDocEnd") > $null; +$vars.Remove("lastCharPos") > $null; $vars.Remove("docEnd") > $null; +$vars.Remove("midEmptySpace") > $null; +$vars.Remove("bufferEnd") > $null; +$vars.Remove("endExclusive") > $null; # 3.b. Now all of the remaining vars can be deduced from standard vars foreach ($var in $vars) { - # Extract the standard var from the name - $standardVar = $var.Contains("Left") ? $var.Split("Left") : $var.Substring(0, $var.length - 3); + # Figure out what heuristic to use + $segmentHeuristic = $var.Contains("segment"); + $leftHeuristic = $var.Contains("Left"); + $movementHeuristic = $var -match ".*\d+.*"; - # i. Contains number --> requires movement - if ($var -match ".*\d+.*") + # i. Contains "segment" --> define point at the beginning of a text segment + if ($segmentHeuristic) { + $result += "constexpr til::point {0}{{ {1}, {2}.y() }};" -f $var, $var.Substring(0, 8), $var.Substring(9, $var.Length - $var.IndexOf("L") - 1); + } + # ii. Contains number --> requires movement + elseif ($movementHeuristic) + { + # everything excluding last 3 characters denotes the standard variable + # we're based on. + $standardVar = $var.Substring(0, $var.length - 3); + # 3rd to last character denotes the movement direction # P --> plus/forwards # M --> minus/backwards @@ -101,10 +121,11 @@ foreach ($var in $vars) Default { Write-Host "Error: unknown variable movement type" -ForegroundColor Red } } } - # ii. Contains "Left" --> set X to left - elseif ($var.Contains("Left")) + # iii. Contains "Left" --> set X to left + elseif ($leftHeuristic) { - $result += "constexpr til::point " + $var + "{ bufferSize.left(), " + $standardVar + ".y() };"; + $standardVar = $var.Split("Left")[0] + $result += "constexpr til::point {0}{{ bufferSize.left(), {1}.y() }};" -f $var, $standardVar; } $result += "`n"; } diff --git a/tools/TestTableWriter/README.md b/tools/TestTableWriter/README.md index a708f1695..0cd6aff32 100644 --- a/tools/TestTableWriter/README.md +++ b/tools/TestTableWriter/README.md @@ -44,21 +44,21 @@ The Test Table Writer was written as a method to generate UI Automation tests fo - "Command Arguments" --> `$(TargetPath) /name:*uiatextrange*generated* /inproc` # Position chart -The text buffer is assumed to be partially filled. Specifically, the top half of the text buffer contains text, and each row is filled with 9 segments of alternating text. For visualization, +The text buffer is assumed to be partially filled. Specifically, the top half of the text buffer contains text, and each row is filled with 10 segments of alternating text. For visualization, the ascii diagram below shows what the text buffer may look like. ``` -+---------------------------+ -|1XX XXX X2X XXX XXX| -|XXX XXX XXX XXX XXX| -|XXX XXX X3X XXX XXX| -|XXX XXX XXX XXX XXX| -|XXX XXX X4X XXX XX5| -|6 | -| | -| 7 | -| | -| 8| -+---------------------------+ ++------------------------------+ +|1XX XXX X2X XXX XXX | +|XXX XXX XXX XXX XXX | +|XXX XXX X3X XXX XXX | +|XXX XXX XXX XXX XXX | +|XXX XXX X4X XXX XX5 | +|6 | +| | +| 7 | +| | +| 8| ++------------------------------+ 9 ``` The following positions are being tested: @@ -84,6 +84,11 @@ Each position above already has a predefined variable name. However, a few heuri - `C`: move by character. For simplicity, assumes that each character is one-cell wide. - `PL`, `ML`: - same as above, except move by line. For simplicity, assumes that you won't hit a buffer boundary. +- `segment#L` + - This is mainly used for word navigation to target a segment of text in the buffer. + - `segment#` refers to the beginning of a segment of text in a row. The leftmost run of text is `segment0`, whereas the rightmost run of text is `segment4`. + - `L` refers to the line number we're targeting, relative to the `` variable. For example, `Lorigin` means that the y-position should be that of `origin`. + - Overall, this allows us to target the beginning of segments of text. `segment0Lorigin` and `segment0LmidTop` both refer to the beginning of the first segment of text on the top line (aka `origin`). # Helpful terms and concepts - *degenerate*: the text range encompasses no text. Also, means the start and end endpoints are the same. diff --git a/tools/TestTableWriter/UiaTests.csv b/tools/TestTableWriter/UiaTests.csv index 70f56a579..088283b25 100644 --- a/tools/TestTableWriter/UiaTests.csv +++ b/tools/TestTableWriter/UiaTests.csv @@ -62,195 +62,280 @@ FALSE,3,TextUnit_Line,5,midHistory,midHistoryP1C,5,midHistoryP5L,midHistoryP6L,F TRUE,1,TextUnit_Document,-5,origin,origin,0,origin,origin,FALSE TRUE,1,TextUnit_Document,-1,origin,origin,0,origin,origin,FALSE TRUE,1,TextUnit_Document,0,origin,origin,0,origin,origin,FALSE -TRUE,1,TextUnit_Document,1,origin,origin,1,endExclusive,endExclusive,FALSE -TRUE,1,TextUnit_Document,5,origin,origin,1,endExclusive,endExclusive,FALSE -FALSE,1,TextUnit_Document,-5,origin,originP1C,0,origin,endExclusive,FALSE -FALSE,1,TextUnit_Document,-1,origin,originP1C,0,origin,endExclusive,FALSE -FALSE,1,TextUnit_Document,0,origin,originP1C,0,origin,endExclusive,FALSE -FALSE,1,TextUnit_Document,1,origin,originP1C,0,origin,endExclusive,FALSE -FALSE,1,TextUnit_Document,5,origin,originP1C,0,origin,endExclusive,FALSE +TRUE,1,TextUnit_Document,1,origin,origin,1,docEnd,docEnd,FALSE +TRUE,1,TextUnit_Document,5,origin,origin,1,docEnd,docEnd,FALSE +FALSE,1,TextUnit_Document,-5,origin,originP1C,0,origin,docEnd,FALSE +FALSE,1,TextUnit_Document,-1,origin,originP1C,0,origin,docEnd,FALSE +FALSE,1,TextUnit_Document,0,origin,originP1C,0,origin,docEnd,FALSE +FALSE,1,TextUnit_Document,1,origin,originP1C,0,origin,docEnd,FALSE +FALSE,1,TextUnit_Document,5,origin,originP1C,0,origin,docEnd,FALSE TRUE,2,TextUnit_Document,-5,midTop,midTop,-1,origin,origin,FALSE TRUE,2,TextUnit_Document,-1,midTop,midTop,-1,origin,origin,FALSE TRUE,2,TextUnit_Document,0,midTop,midTop,0,midTop,midTop,FALSE -TRUE,2,TextUnit_Document,1,midTop,midTop,1,endExclusive,endExclusive,FALSE -TRUE,2,TextUnit_Document,5,midTop,midTop,1,endExclusive,endExclusive,FALSE -FALSE,2,TextUnit_Document,-5,midTop,midTopP1C,0,origin,endExclusive,FALSE -FALSE,2,TextUnit_Document,-1,midTop,midTopP1C,0,origin,endExclusive,FALSE -FALSE,2,TextUnit_Document,0,midTop,midTopP1C,0,origin,endExclusive,FALSE -FALSE,2,TextUnit_Document,1,midTop,midTopP1C,0,origin,endExclusive,FALSE -FALSE,2,TextUnit_Document,5,midTop,midTopP1C,0,origin,endExclusive,FALSE +TRUE,2,TextUnit_Document,1,midTop,midTop,1,docEnd,docEnd,FALSE +TRUE,2,TextUnit_Document,5,midTop,midTop,1,docEnd,docEnd,FALSE +FALSE,2,TextUnit_Document,-5,midTop,midTopP1C,0,origin,docEnd,FALSE +FALSE,2,TextUnit_Document,-1,midTop,midTopP1C,0,origin,docEnd,FALSE +FALSE,2,TextUnit_Document,0,midTop,midTopP1C,0,origin,docEnd,FALSE +FALSE,2,TextUnit_Document,1,midTop,midTopP1C,0,origin,docEnd,FALSE +FALSE,2,TextUnit_Document,5,midTop,midTopP1C,0,origin,docEnd,FALSE TRUE,3,TextUnit_Document,-5,midHistory,midHistory,-1,origin,origin,FALSE TRUE,3,TextUnit_Document,-1,midHistory,midHistory,-1,origin,origin,FALSE TRUE,3,TextUnit_Document,0,midHistory,midHistory,0,midHistory,midHistory,FALSE -TRUE,3,TextUnit_Document,1,midHistory,midHistory,1,endExclusive,endExclusive,FALSE -TRUE,3,TextUnit_Document,5,midHistory,midHistory,1,endExclusive,endExclusive,FALSE -FALSE,3,TextUnit_Document,-5,midHistory,midHistoryP1C,0,origin,endExclusive,FALSE -FALSE,3,TextUnit_Document,-1,midHistory,midHistoryP1C,0,origin,endExclusive,FALSE -FALSE,3,TextUnit_Document,0,midHistory,midHistoryP1C,0,origin,endExclusive,FALSE -FALSE,3,TextUnit_Document,1,midHistory,midHistoryP1C,0,origin,endExclusive,FALSE -FALSE,3,TextUnit_Document,5,midHistory,midHistoryP1C,0,origin,endExclusive,FALSE -TRUE,8,TextUnit_Character,-5,bufferEnd,bufferEnd,-5,bufferEndM5C,bufferEndM5C,FALSE -TRUE,8,TextUnit_Character,-1,bufferEnd,bufferEnd,-1,bufferEndM1C,bufferEndM1C,FALSE -TRUE,8,TextUnit_Character,0,bufferEnd,bufferEnd,0,bufferEnd,bufferEnd,FALSE -TRUE,8,TextUnit_Character,1,bufferEnd,bufferEnd,1,endExclusive,endExclusive,TRUE -TRUE,8,TextUnit_Character,5,bufferEnd,bufferEnd,1,endExclusive,endExclusive,TRUE -FALSE,8,TextUnit_Character,-5,bufferEnd,endExclusive,-5,bufferEndM5C,bufferEndM4C,FALSE -FALSE,8,TextUnit_Character,-1,bufferEnd,endExclusive,-1,bufferEndM1C,bufferEnd,FALSE -FALSE,8,TextUnit_Character,0,bufferEnd,endExclusive,0,bufferEnd,endExclusive,FALSE -FALSE,8,TextUnit_Character,1,bufferEnd,endExclusive,0,bufferEnd,endExclusive,FALSE -FALSE,8,TextUnit_Character,5,bufferEnd,endExclusive,0,bufferEnd,endExclusive,FALSE -TRUE,8,TextUnit_Line,-5,bufferEnd,bufferEnd,-5,bufferEndM4L,bufferEndM4L,FALSE -TRUE,8,TextUnit_Line,-1,bufferEnd,bufferEnd,-1,bufferEndLeft,bufferEndLeft,FALSE -TRUE,8,TextUnit_Line,0,bufferEnd,bufferEnd,0,bufferEnd,bufferEnd,FALSE -TRUE,8,TextUnit_Line,1,bufferEnd,bufferEnd,1,endExclusive,endExclusive,TRUE -TRUE,8,TextUnit_Line,5,bufferEnd,bufferEnd,1,endExclusive,endExclusive,TRUE -FALSE,8,TextUnit_Line,-5,bufferEnd,endExclusive,-5,bufferEndM5L,bufferEndM4L,TRUE -FALSE,8,TextUnit_Line,-1,bufferEnd,endExclusive,-1,bufferEndM1L,bufferEndLeft,TRUE -FALSE,8,TextUnit_Line,0,bufferEnd,endExclusive,0,bufferEndLeft,endExclusive,TRUE -FALSE,8,TextUnit_Line,1,bufferEnd,endExclusive,0,bufferEndLeft,endExclusive,TRUE -FALSE,8,TextUnit_Line,5,bufferEnd,endExclusive,0,bufferEndLeft,endExclusive,TRUE +TRUE,3,TextUnit_Document,1,midHistory,midHistory,1,docEnd,docEnd,FALSE +TRUE,3,TextUnit_Document,5,midHistory,midHistory,1,docEnd,docEnd,FALSE +FALSE,3,TextUnit_Document,-5,midHistory,midHistoryP1C,0,origin,docEnd,FALSE +FALSE,3,TextUnit_Document,-1,midHistory,midHistoryP1C,0,origin,docEnd,FALSE +FALSE,3,TextUnit_Document,0,midHistory,midHistoryP1C,0,origin,docEnd,FALSE +FALSE,3,TextUnit_Document,1,midHistory,midHistoryP1C,0,origin,docEnd,FALSE +FALSE,3,TextUnit_Document,5,midHistory,midHistoryP1C,0,origin,docEnd,FALSE +TRUE,8,TextUnit_Character,-5,bufferEnd,bufferEnd,-5,docEndM5C,docEndM5C,FALSE +TRUE,8,TextUnit_Character,-1,bufferEnd,bufferEnd,-1,docEndM1C,docEndM1C,FALSE +TRUE,8,TextUnit_Character,0,bufferEnd,bufferEnd,0,docEnd,docEnd,FALSE +TRUE,8,TextUnit_Character,1,bufferEnd,bufferEnd,0,docEnd,docEnd,FALSE +TRUE,8,TextUnit_Character,5,bufferEnd,bufferEnd,0,docEnd,docEnd,FALSE +FALSE,8,TextUnit_Character,-5,bufferEnd,endExclusive,-5,docEndM5C,docEndM5C,FALSE +FALSE,8,TextUnit_Character,-1,bufferEnd,endExclusive,-1,docEndM1C,docEndM1C,FALSE +FALSE,8,TextUnit_Character,0,bufferEnd,endExclusive,0,docEnd,docEnd,FALSE +FALSE,8,TextUnit_Character,1,bufferEnd,endExclusive,0,docEnd,docEnd,FALSE +FALSE,8,TextUnit_Character,5,bufferEnd,endExclusive,0,docEnd,docEnd,FALSE +TRUE,8,TextUnit_Line,-5,bufferEnd,bufferEnd,-5,docEndM5L,docEndM5L,FALSE +TRUE,8,TextUnit_Line,-1,bufferEnd,bufferEnd,-1,docEndM1L,docEndM1L,FALSE +TRUE,8,TextUnit_Line,0,bufferEnd,bufferEnd,0,docEnd,docEnd,FALSE +TRUE,8,TextUnit_Line,1,bufferEnd,bufferEnd,0,docEnd,docEnd,FALSE +TRUE,8,TextUnit_Line,5,bufferEnd,bufferEnd,0,docEnd,docEnd,FALSE +FALSE,8,TextUnit_Line,-5,bufferEnd,endExclusive,-5,docEndM5L,docEndM5L,FALSE +FALSE,8,TextUnit_Line,-1,bufferEnd,endExclusive,-1,docEndM1L,docEndM1L,FALSE +FALSE,8,TextUnit_Line,0,bufferEnd,endExclusive,0,docEnd,docEnd,FALSE +FALSE,8,TextUnit_Line,1,bufferEnd,endExclusive,0,docEnd,docEnd,FALSE +FALSE,8,TextUnit_Line,5,bufferEnd,endExclusive,0,docEnd,docEnd,FALSE TRUE,8,TextUnit_Document,-5,bufferEnd,bufferEnd,-1,origin,origin,FALSE TRUE,8,TextUnit_Document,-1,bufferEnd,bufferEnd,-1,origin,origin,FALSE -TRUE,8,TextUnit_Document,0,bufferEnd,bufferEnd,0,bufferEnd,bufferEnd,FALSE -TRUE,8,TextUnit_Document,1,bufferEnd,bufferEnd,1,endExclusive,endExclusive,TRUE -TRUE,8,TextUnit_Document,5,bufferEnd,bufferEnd,1,endExclusive,endExclusive,TRUE -FALSE,8,TextUnit_Document,-5,bufferEnd,endExclusive,0,origin,endExclusive,TRUE -FALSE,8,TextUnit_Document,-1,bufferEnd,endExclusive,0,origin,endExclusive,TRUE -FALSE,8,TextUnit_Document,0,bufferEnd,endExclusive,0,origin,endExclusive,TRUE -FALSE,8,TextUnit_Document,1,bufferEnd,endExclusive,0,origin,endExclusive,TRUE -FALSE,8,TextUnit_Document,5,bufferEnd,endExclusive,0,origin,endExclusive,TRUE -TRUE,9,TextUnit_Character,-5,endExclusive,endExclusive,-5,bufferEndM4C,bufferEndM4C,FALSE -TRUE,9,TextUnit_Character,-1,endExclusive,endExclusive,-1,bufferEnd,bufferEnd,FALSE -TRUE,9,TextUnit_Character,0,endExclusive,endExclusive,0,endExclusive,endExclusive,FALSE -TRUE,9,TextUnit_Character,1,endExclusive,endExclusive,0,endExclusive,endExclusive,FALSE -TRUE,9,TextUnit_Character,5,endExclusive,endExclusive,0,endExclusive,endExclusive,FALSE -TRUE,9,TextUnit_Line,-5,endExclusive,endExclusive,-5,bufferEndM4L,bufferEndM4L,FALSE -TRUE,9,TextUnit_Line,-1,endExclusive,endExclusive,-1,bufferEndLeft,bufferEndLeft,FALSE -TRUE,9,TextUnit_Line,0,endExclusive,endExclusive,0,endExclusive,endExclusive,FALSE -TRUE,9,TextUnit_Line,1,endExclusive,endExclusive,0,endExclusive,endExclusive,FALSE -TRUE,9,TextUnit_Line,5,endExclusive,endExclusive,0,endExclusive,endExclusive,FALSE +TRUE,8,TextUnit_Document,0,bufferEnd,bufferEnd,0,docEnd,docEnd,FALSE +TRUE,8,TextUnit_Document,1,bufferEnd,bufferEnd,0,docEnd,docEnd,FALSE +TRUE,8,TextUnit_Document,5,bufferEnd,bufferEnd,0,docEnd,docEnd,FALSE +FALSE,8,TextUnit_Document,-5,bufferEnd,endExclusive,-1,origin,origin,FALSE +FALSE,8,TextUnit_Document,-1,bufferEnd,endExclusive,-1,origin,origin,FALSE +FALSE,8,TextUnit_Document,0,bufferEnd,endExclusive,0,docEnd,docEnd,FALSE +FALSE,8,TextUnit_Document,1,bufferEnd,endExclusive,0,docEnd,docEnd,FALSE +FALSE,8,TextUnit_Document,5,bufferEnd,endExclusive,0,docEnd,docEnd,FALSE +TRUE,9,TextUnit_Character,-5,endExclusive,endExclusive,-5,docEndM5C,docEndM5C,FALSE +TRUE,9,TextUnit_Character,-1,endExclusive,endExclusive,-1,docEndM1C,docEndM1C,FALSE +TRUE,9,TextUnit_Character,0,endExclusive,endExclusive,0,docEnd,docEnd,FALSE +TRUE,9,TextUnit_Character,1,endExclusive,endExclusive,0,docEnd,docEnd,FALSE +TRUE,9,TextUnit_Character,5,endExclusive,endExclusive,0,docEnd,docEnd,FALSE +TRUE,9,TextUnit_Line,-5,endExclusive,endExclusive,-5,docEndM5L,docEndM5L,FALSE +TRUE,9,TextUnit_Line,-1,endExclusive,endExclusive,-1,docEndM1L,docEndM1L,FALSE +TRUE,9,TextUnit_Line,0,endExclusive,endExclusive,0,docEnd,docEnd,FALSE +TRUE,9,TextUnit_Line,1,endExclusive,endExclusive,0,docEnd,docEnd,FALSE +TRUE,9,TextUnit_Line,5,endExclusive,endExclusive,0,docEnd,docEnd,FALSE TRUE,9,TextUnit_Document,-5,endExclusive,endExclusive,-1,origin,origin,FALSE TRUE,9,TextUnit_Document,-1,endExclusive,endExclusive,-1,origin,origin,FALSE -TRUE,9,TextUnit_Document,0,endExclusive,endExclusive,0,endExclusive,endExclusive,FALSE -TRUE,9,TextUnit_Document,1,endExclusive,endExclusive,0,endExclusive,endExclusive,FALSE -TRUE,9,TextUnit_Document,5,endExclusive,endExclusive,0,endExclusive,endExclusive,FALSE -TRUE,4,TextUnit_Character,-5,midDocEnd,midDocEnd,-5,midDocEndM5C,midDocEndM5C,TRUE -TRUE,4,TextUnit_Character,-1,midDocEnd,midDocEnd,-1,midDocEndM1C,midDocEndM1C,TRUE -TRUE,4,TextUnit_Character,0,midDocEnd,midDocEnd,0,midDocEnd,midDocEnd,TRUE -TRUE,4,TextUnit_Character,1,midDocEnd,midDocEnd,1,midDocEndP1C,midDocEndP1C,TRUE -TRUE,4,TextUnit_Character,5,midDocEnd,midDocEnd,5,midDocEndP5C,midDocEndP5C,TRUE -FALSE,4,TextUnit_Character,-5,midDocEnd,midDocEndP1C,-5,midDocEndM5C,midDocEndM4C,TRUE -FALSE,4,TextUnit_Character,-1,midDocEnd,midDocEndP1C,-1,midDocEndM1C,midDocEnd,TRUE -FALSE,4,TextUnit_Character,0,midDocEnd,midDocEndP1C,0,midDocEnd,midDocEndP1C,TRUE -FALSE,4,TextUnit_Character,1,midDocEnd,midDocEndP1C,1,midDocEndP1C,midDocEndP2C,TRUE -FALSE,4,TextUnit_Character,5,midDocEnd,midDocEndP1C,5,midDocEndP5C,midDocEndP6C,TRUE -TRUE,4,TextUnit_Line,-5,midDocEnd,midDocEnd,-5,midDocEndM4L,midDocEndM4L,TRUE -TRUE,4,TextUnit_Line,-1,midDocEnd,midDocEnd,-1,midDocEndLeft,midDocEndLeft,TRUE -TRUE,4,TextUnit_Line,0,midDocEnd,midDocEnd,0,midDocEnd,midDocEnd,TRUE -TRUE,4,TextUnit_Line,1,midDocEnd,midDocEnd,1,docEnd,docEnd,TRUE -TRUE,4,TextUnit_Line,5,midDocEnd,midDocEnd,1,docEnd,docEnd,TRUE -FALSE,4,TextUnit_Line,-5,midDocEnd,midDocEndP1C,-5,midDocEndM5L,midDocEndM4L,TRUE -FALSE,4,TextUnit_Line,-1,midDocEnd,midDocEndP1C,-1,midDocEndM1L,midDocEndLeft,TRUE -FALSE,4,TextUnit_Line,0,midDocEnd,midDocEndP1C,0,midDocEndLeft,docEnd,TRUE -FALSE,4,TextUnit_Line,1,midDocEnd,midDocEndP1C,0,midDocEndLeft,docEnd,TRUE -FALSE,4,TextUnit_Line,5,midDocEnd,midDocEndP1C,0,midDocEndLeft,docEnd,TRUE -TRUE,4,TextUnit_Document,-5,midDocEnd,midDocEnd,-1,origin,origin,TRUE -TRUE,4,TextUnit_Document,-1,midDocEnd,midDocEnd,-1,origin,origin,TRUE -TRUE,4,TextUnit_Document,0,midDocEnd,midDocEnd,0,midDocEnd,midDocEnd,TRUE -TRUE,4,TextUnit_Document,1,midDocEnd,midDocEnd,1,docEnd,docEnd,TRUE -TRUE,4,TextUnit_Document,5,midDocEnd,midDocEnd,1,docEnd,docEnd,TRUE -FALSE,4,TextUnit_Document,-5,midDocEnd,midDocEndP1C,0,origin,docEnd,TRUE -FALSE,4,TextUnit_Document,-1,midDocEnd,midDocEndP1C,0,origin,docEnd,TRUE -FALSE,4,TextUnit_Document,0,midDocEnd,midDocEndP1C,0,origin,docEnd,TRUE -FALSE,4,TextUnit_Document,1,midDocEnd,midDocEndP1C,0,origin,docEnd,TRUE -FALSE,4,TextUnit_Document,5,midDocEnd,midDocEndP1C,0,origin,docEnd,TRUE -TRUE,5,TextUnit_Character,-5,lastCharPos,lastCharPos,-5,lastCharPosM5C,lastCharPosM5C,TRUE -TRUE,5,TextUnit_Character,-1,lastCharPos,lastCharPos,-1,lastCharPosM1C,lastCharPosM1C,TRUE -TRUE,5,TextUnit_Character,0,lastCharPos,lastCharPos,0,lastCharPos,lastCharPos,TRUE -TRUE,5,TextUnit_Character,1,lastCharPos,lastCharPos,1,docEnd,docEnd,TRUE -TRUE,5,TextUnit_Character,5,lastCharPos,lastCharPos,1,docEnd,docEnd,TRUE -FALSE,5,TextUnit_Character,-5,lastCharPos,lastCharPosP1C,-5,lastCharPosM5C,lastCharPosM4C,TRUE -FALSE,5,TextUnit_Character,-1,lastCharPos,lastCharPosP1C,-1,lastCharPosM1C,lastCharPos,TRUE -FALSE,5,TextUnit_Character,0,lastCharPos,lastCharPosP1C,0,lastCharPos,docEnd,TRUE -FALSE,5,TextUnit_Character,1,lastCharPos,lastCharPosP1C,0,lastCharPos,docEnd,TRUE -FALSE,5,TextUnit_Character,5,lastCharPos,lastCharPosP1C,0,lastCharPos,docEnd,TRUE -TRUE,5,TextUnit_Line,-5,lastCharPos,lastCharPos,-5,lastCharPosM4L,lastCharPosM4L,TRUE -TRUE,5,TextUnit_Line,-1,lastCharPos,lastCharPos,-1,lastCharPosLeft,lastCharPosLeft,TRUE -TRUE,5,TextUnit_Line,0,lastCharPos,lastCharPos,0,lastCharPos,lastCharPos,TRUE -TRUE,5,TextUnit_Line,1,lastCharPos,lastCharPos,1,docEnd,docEnd,TRUE -TRUE,5,TextUnit_Line,5,lastCharPos,lastCharPos,1,docEnd,docEnd,TRUE -FALSE,5,TextUnit_Line,-5,lastCharPos,lastCharPosP1C,-5,lastCharPosM5L,lastCharPosM4L,TRUE -FALSE,5,TextUnit_Line,-1,lastCharPos,lastCharPosP1C,-1,lastCharPosM1L,lastCharPosLeft,TRUE -FALSE,5,TextUnit_Line,0,lastCharPos,lastCharPosP1C,0,lastCharPosLeft,docEnd,TRUE -FALSE,5,TextUnit_Line,1,lastCharPos,lastCharPosP1C,0,lastCharPosLeft,docEnd,TRUE -FALSE,5,TextUnit_Line,5,lastCharPos,lastCharPosP1C,0,lastCharPosLeft,docEnd,TRUE -TRUE,5,TextUnit_Document,-5,lastCharPos,lastCharPos,-1,origin,origin,TRUE -TRUE,5,TextUnit_Document,-1,lastCharPos,lastCharPos,-1,origin,origin,TRUE -TRUE,5,TextUnit_Document,0,lastCharPos,lastCharPos,0,lastCharPos,lastCharPos,TRUE -TRUE,5,TextUnit_Document,1,lastCharPos,lastCharPos,1,docEnd,docEnd,TRUE -TRUE,5,TextUnit_Document,5,lastCharPos,lastCharPos,1,docEnd,docEnd,TRUE -FALSE,5,TextUnit_Document,-5,lastCharPos,lastCharPosP1C,0,origin,docEnd,TRUE -FALSE,5,TextUnit_Document,-1,lastCharPos,lastCharPosP1C,0,origin,docEnd,TRUE -FALSE,5,TextUnit_Document,0,lastCharPos,lastCharPosP1C,0,origin,docEnd,TRUE -FALSE,5,TextUnit_Document,1,lastCharPos,lastCharPosP1C,0,origin,docEnd,TRUE -FALSE,5,TextUnit_Document,5,lastCharPos,lastCharPosP1C,0,origin,docEnd,TRUE -TRUE,6,TextUnit_Character,-5,docEnd,docEnd,-5,docEndM5C,docEndM5C,TRUE -TRUE,6,TextUnit_Character,-1,docEnd,docEnd,-1,docEndM1C,docEndM1C,TRUE -TRUE,6,TextUnit_Character,0,docEnd,docEnd,0,docEnd,docEnd,TRUE -TRUE,6,TextUnit_Character,1,docEnd,docEnd,0,docEnd,docEnd,TRUE -TRUE,6,TextUnit_Character,5,docEnd,docEnd,0,docEnd,docEnd,TRUE -FALSE,6,TextUnit_Character,-5,docEnd,docEndP1C,-5,docEndM5C,docEndM5C,TRUE -FALSE,6,TextUnit_Character,-1,docEnd,docEndP1C,-1,docEndM1C,docEndM1C,TRUE -FALSE,6,TextUnit_Character,0,docEnd,docEndP1C,0,docEnd,docEnd,TRUE -FALSE,6,TextUnit_Character,1,docEnd,docEndP1C,0,docEnd,docEnd,TRUE -FALSE,6,TextUnit_Character,5,docEnd,docEndP1C,0,docEnd,docEnd,TRUE -TRUE,6,TextUnit_Line,-5,docEnd,docEnd,-5,docEndM4L,docEndM4L,TRUE -TRUE,6,TextUnit_Line,-1,docEnd,docEnd,-1,docEndLeft,docEndLeft,TRUE -TRUE,6,TextUnit_Line,0,docEnd,docEnd,0,docEnd,docEnd,TRUE -TRUE,6,TextUnit_Line,1,docEnd,docEnd,0,docEnd,docEnd,TRUE -TRUE,6,TextUnit_Line,5,docEnd,docEnd,0,docEnd,docEnd,TRUE -FALSE,6,TextUnit_Line,-5,docEnd,docEndP1C,-5,docEndM4L,docEndM4L,TRUE -FALSE,6,TextUnit_Line,-1,docEnd,docEndP1C,-1,docEndLeft,docEndLeft,TRUE -FALSE,6,TextUnit_Line,0,docEnd,docEndP1C,0,docEnd,docEnd,TRUE -FALSE,6,TextUnit_Line,1,docEnd,docEndP1C,0,docEnd,docEnd,TRUE -FALSE,6,TextUnit_Line,5,docEnd,docEndP1C,0,docEnd,docEnd,TRUE -TRUE,6,TextUnit_Document,-5,docEnd,docEnd,-1,origin,origin,TRUE -TRUE,6,TextUnit_Document,-1,docEnd,docEnd,-1,origin,origin,TRUE -TRUE,6,TextUnit_Document,0,docEnd,docEnd,0,docEnd,docEnd,TRUE -TRUE,6,TextUnit_Document,1,docEnd,docEnd,0,docEnd,docEnd,TRUE -TRUE,6,TextUnit_Document,5,docEnd,docEnd,0,docEnd,docEnd,TRUE -FALSE,6,TextUnit_Document,-5,docEnd,docEndP1C,-1,origin,origin,TRUE -FALSE,6,TextUnit_Document,-1,docEnd,docEndP1C,-1,origin,origin,TRUE -FALSE,6,TextUnit_Document,0,docEnd,docEndP1C,0,docEnd,docEnd,TRUE -FALSE,6,TextUnit_Document,1,docEnd,docEndP1C,0,docEnd,docEnd,TRUE -FALSE,6,TextUnit_Document,5,docEnd,docEndP1C,0,docEnd,docEnd,TRUE -TRUE,7,TextUnit_Character,-5,midEmptySpace,midEmptySpace,-5,docEndM5C,docEndM5C,TRUE -TRUE,7,TextUnit_Character,-1,midEmptySpace,midEmptySpace,-1,docEndM1C,docEndM1C,TRUE -TRUE,7,TextUnit_Character,0,midEmptySpace,midEmptySpace,0,docEnd,docEnd,TRUE -TRUE,7,TextUnit_Character,1,midEmptySpace,midEmptySpace,0,docEnd,docEnd,TRUE -TRUE,7,TextUnit_Character,5,midEmptySpace,midEmptySpace,0,docEnd,docEnd,TRUE -FALSE,7,TextUnit_Character,-5,midEmptySpace,midEmptySpaceP1C,-5,docEndM5C,docEndM5C,TRUE -FALSE,7,TextUnit_Character,-1,midEmptySpace,midEmptySpaceP1C,-1,docEndM1C,docEndM1C,TRUE -FALSE,7,TextUnit_Character,0,midEmptySpace,midEmptySpaceP1C,0,docEnd,docEnd,TRUE -FALSE,7,TextUnit_Character,1,midEmptySpace,midEmptySpaceP1C,0,docEnd,docEnd,TRUE -FALSE,7,TextUnit_Character,5,midEmptySpace,midEmptySpaceP1C,0,docEnd,docEnd,TRUE -TRUE,7,TextUnit_Line,-5,midEmptySpace,midEmptySpace,-5,docEndM4L,docEndM4L,TRUE -TRUE,7,TextUnit_Line,-1,midEmptySpace,midEmptySpace,-1,docEndLeft,docEndLeft,TRUE -TRUE,7,TextUnit_Line,0,midEmptySpace,midEmptySpace,0,docEnd,docEnd,TRUE -TRUE,7,TextUnit_Line,1,midEmptySpace,midEmptySpace,0,docEnd,docEnd,TRUE -TRUE,7,TextUnit_Line,5,midEmptySpace,midEmptySpace,0,docEnd,docEnd,TRUE -FALSE,7,TextUnit_Line,-5,midEmptySpace,midEmptySpaceP1C,-5,docEndM4L,docEndM4L,TRUE -FALSE,7,TextUnit_Line,-1,midEmptySpace,midEmptySpaceP1C,-1,docEndLeft,docEndLeft,TRUE -FALSE,7,TextUnit_Line,0,midEmptySpace,midEmptySpaceP1C,0,docEnd,docEnd,TRUE -FALSE,7,TextUnit_Line,1,midEmptySpace,midEmptySpaceP1C,0,docEnd,docEnd,TRUE -FALSE,7,TextUnit_Line,5,midEmptySpace,midEmptySpaceP1C,0,docEnd,docEnd,TRUE -TRUE,7,TextUnit_Document,-5,midEmptySpace,midEmptySpace,-1,origin,origin,TRUE -TRUE,7,TextUnit_Document,-1,midEmptySpace,midEmptySpace,-1,origin,origin,TRUE -TRUE,7,TextUnit_Document,0,midEmptySpace,midEmptySpace,0,docEnd,docEnd,TRUE -TRUE,7,TextUnit_Document,1,midEmptySpace,midEmptySpace,0,docEnd,docEnd,TRUE -TRUE,7,TextUnit_Document,5,midEmptySpace,midEmptySpace,0,docEnd,docEnd,TRUE -FALSE,7,TextUnit_Document,-5,midEmptySpace,midEmptySpaceP1C,-1,origin,origin,TRUE -FALSE,7,TextUnit_Document,-1,midEmptySpace,midEmptySpaceP1C,-1,origin,origin,TRUE -FALSE,7,TextUnit_Document,0,midEmptySpace,midEmptySpaceP1C,0,docEnd,docEnd,TRUE -FALSE,7,TextUnit_Document,1,midEmptySpace,midEmptySpaceP1C,0,docEnd,docEnd,TRUE -FALSE,7,TextUnit_Document,5,midEmptySpace,midEmptySpaceP1C,0,docEnd,docEnd,TRUE +TRUE,9,TextUnit_Document,0,endExclusive,endExclusive,0,docEnd,docEnd,FALSE +TRUE,9,TextUnit_Document,1,endExclusive,endExclusive,0,docEnd,docEnd,FALSE +TRUE,9,TextUnit_Document,5,endExclusive,endExclusive,0,docEnd,docEnd,FALSE +TRUE,4,TextUnit_Character,-5,midDocEnd,midDocEnd,-5,midDocEndM5C,midDocEndM5C,FALSE +TRUE,4,TextUnit_Character,-1,midDocEnd,midDocEnd,-1,midDocEndM1C,midDocEndM1C,FALSE +TRUE,4,TextUnit_Character,0,midDocEnd,midDocEnd,0,midDocEnd,midDocEnd,FALSE +TRUE,4,TextUnit_Character,1,midDocEnd,midDocEnd,1,midDocEndP1C,midDocEndP1C,FALSE +TRUE,4,TextUnit_Character,5,midDocEnd,midDocEnd,5,midDocEndP5C,midDocEndP5C,FALSE +FALSE,4,TextUnit_Character,-5,midDocEnd,midDocEndP1C,-5,midDocEndM5C,midDocEndM4C,FALSE +FALSE,4,TextUnit_Character,-1,midDocEnd,midDocEndP1C,-1,midDocEndM1C,midDocEnd,FALSE +FALSE,4,TextUnit_Character,0,midDocEnd,midDocEndP1C,0,midDocEnd,midDocEndP1C,FALSE +FALSE,4,TextUnit_Character,1,midDocEnd,midDocEndP1C,1,midDocEndP1C,midDocEndP2C,FALSE +FALSE,4,TextUnit_Character,5,midDocEnd,midDocEndP1C,5,midDocEndP5C,midDocEndP6C,FALSE +TRUE,4,TextUnit_Line,-5,midDocEnd,midDocEnd,-5,midDocEndM4L,midDocEndM4L,FALSE +TRUE,4,TextUnit_Line,-1,midDocEnd,midDocEnd,-1,midDocEndLeft,midDocEndLeft,FALSE +TRUE,4,TextUnit_Line,0,midDocEnd,midDocEnd,0,midDocEnd,midDocEnd,FALSE +TRUE,4,TextUnit_Line,1,midDocEnd,midDocEnd,1,docEnd,docEnd,FALSE +TRUE,4,TextUnit_Line,5,midDocEnd,midDocEnd,1,docEnd,docEnd,FALSE +FALSE,4,TextUnit_Line,-5,midDocEnd,midDocEndP1C,-5,midDocEndM5L,midDocEndM4L,FALSE +FALSE,4,TextUnit_Line,-1,midDocEnd,midDocEndP1C,-1,midDocEndM1L,midDocEndLeft,FALSE +FALSE,4,TextUnit_Line,0,midDocEnd,midDocEndP1C,0,midDocEndLeft,docEnd,FALSE +FALSE,4,TextUnit_Line,1,midDocEnd,midDocEndP1C,0,midDocEndLeft,docEnd,FALSE +FALSE,4,TextUnit_Line,5,midDocEnd,midDocEndP1C,0,midDocEndLeft,docEnd,FALSE +TRUE,4,TextUnit_Document,-5,midDocEnd,midDocEnd,-1,origin,origin,FALSE +TRUE,4,TextUnit_Document,-1,midDocEnd,midDocEnd,-1,origin,origin,FALSE +TRUE,4,TextUnit_Document,0,midDocEnd,midDocEnd,0,midDocEnd,midDocEnd,FALSE +TRUE,4,TextUnit_Document,1,midDocEnd,midDocEnd,1,docEnd,docEnd,FALSE +TRUE,4,TextUnit_Document,5,midDocEnd,midDocEnd,1,docEnd,docEnd,FALSE +FALSE,4,TextUnit_Document,-5,midDocEnd,midDocEndP1C,0,origin,docEnd,FALSE +FALSE,4,TextUnit_Document,-1,midDocEnd,midDocEndP1C,0,origin,docEnd,FALSE +FALSE,4,TextUnit_Document,0,midDocEnd,midDocEndP1C,0,origin,docEnd,FALSE +FALSE,4,TextUnit_Document,1,midDocEnd,midDocEndP1C,0,origin,docEnd,FALSE +FALSE,4,TextUnit_Document,5,midDocEnd,midDocEndP1C,0,origin,docEnd,FALSE +TRUE,5,TextUnit_Character,-5,lastCharPos,lastCharPos,-5,lastCharPosM5C,lastCharPosM5C,FALSE +TRUE,5,TextUnit_Character,-1,lastCharPos,lastCharPos,-1,lastCharPosM1C,lastCharPosM1C,FALSE +TRUE,5,TextUnit_Character,0,lastCharPos,lastCharPos,0,lastCharPos,lastCharPos,FALSE +TRUE,5,TextUnit_Character,1,lastCharPos,lastCharPos,1,lastCharPosP1C,lastCharPosP1C,FALSE +TRUE,5,TextUnit_Character,5,lastCharPos,lastCharPos,5,lastCharPosP5C,lastCharPosP5C,FALSE +FALSE,5,TextUnit_Character,-5,lastCharPos,lastCharPosP1C,-5,lastCharPosM5C,lastCharPosM4C,FALSE +FALSE,5,TextUnit_Character,-1,lastCharPos,lastCharPosP1C,-1,lastCharPosM1C,lastCharPos,FALSE +FALSE,5,TextUnit_Character,0,lastCharPos,lastCharPosP1C,0,lastCharPos,lastCharPosP1C,FALSE +FALSE,5,TextUnit_Character,1,lastCharPos,lastCharPosP1C,1,lastCharPosP1C,lastCharPosP2C,FALSE +FALSE,5,TextUnit_Character,5,lastCharPos,lastCharPosP1C,5,lastCharPosP5C,lastCharPosP6C,FALSE +TRUE,5,TextUnit_Line,-5,lastCharPos,lastCharPos,-5,lastCharPosM4L,lastCharPosM4L,FALSE +TRUE,5,TextUnit_Line,-1,lastCharPos,lastCharPos,-1,lastCharPosLeft,lastCharPosLeft,FALSE +TRUE,5,TextUnit_Line,0,lastCharPos,lastCharPos,0,lastCharPos,lastCharPos,FALSE +TRUE,5,TextUnit_Line,1,lastCharPos,lastCharPos,1,docEnd,docEnd,FALSE +TRUE,5,TextUnit_Line,5,lastCharPos,lastCharPos,1,docEnd,docEnd,FALSE +FALSE,5,TextUnit_Line,-5,lastCharPos,lastCharPosP1C,-5,lastCharPosM5L,lastCharPosM4L,FALSE +FALSE,5,TextUnit_Line,-1,lastCharPos,lastCharPosP1C,-1,lastCharPosM1L,lastCharPosLeft,FALSE +FALSE,5,TextUnit_Line,0,lastCharPos,lastCharPosP1C,0,lastCharPosLeft,docEnd,FALSE +FALSE,5,TextUnit_Line,1,lastCharPos,lastCharPosP1C,0,lastCharPosLeft,docEnd,FALSE +FALSE,5,TextUnit_Line,5,lastCharPos,lastCharPosP1C,0,lastCharPosLeft,docEnd,FALSE +TRUE,5,TextUnit_Document,-5,lastCharPos,lastCharPos,-1,origin,origin,FALSE +TRUE,5,TextUnit_Document,-1,lastCharPos,lastCharPos,-1,origin,origin,FALSE +TRUE,5,TextUnit_Document,0,lastCharPos,lastCharPos,0,lastCharPos,lastCharPos,FALSE +TRUE,5,TextUnit_Document,1,lastCharPos,lastCharPos,1,docEnd,docEnd,FALSE +TRUE,5,TextUnit_Document,5,lastCharPos,lastCharPos,1,docEnd,docEnd,FALSE +FALSE,5,TextUnit_Document,-5,lastCharPos,lastCharPosP1C,0,origin,docEnd,FALSE +FALSE,5,TextUnit_Document,-1,lastCharPos,lastCharPosP1C,0,origin,docEnd,FALSE +FALSE,5,TextUnit_Document,0,lastCharPos,lastCharPosP1C,0,origin,docEnd,FALSE +FALSE,5,TextUnit_Document,1,lastCharPos,lastCharPosP1C,0,origin,docEnd,FALSE +FALSE,5,TextUnit_Document,5,lastCharPos,lastCharPosP1C,0,origin,docEnd,FALSE +TRUE,6,TextUnit_Character,-5,docEnd,docEnd,-5,docEndM5C,docEndM5C,FALSE +TRUE,6,TextUnit_Character,-1,docEnd,docEnd,-1,docEndM1C,docEndM1C,FALSE +TRUE,6,TextUnit_Character,0,docEnd,docEnd,0,docEnd,docEnd,FALSE +TRUE,6,TextUnit_Character,1,docEnd,docEnd,0,docEnd,docEnd,FALSE +TRUE,6,TextUnit_Character,5,docEnd,docEnd,0,docEnd,docEnd,FALSE +FALSE,6,TextUnit_Character,-5,docEnd,docEndP1C,-5,docEndM5C,docEndM5C,FALSE +FALSE,6,TextUnit_Character,-1,docEnd,docEndP1C,-1,docEndM1C,docEndM1C,FALSE +FALSE,6,TextUnit_Character,0,docEnd,docEndP1C,0,docEnd,docEnd,FALSE +FALSE,6,TextUnit_Character,1,docEnd,docEndP1C,0,docEnd,docEnd,FALSE +FALSE,6,TextUnit_Character,5,docEnd,docEndP1C,0,docEnd,docEnd,FALSE +TRUE,6,TextUnit_Line,-5,docEnd,docEnd,-5,docEndM5L,docEndM5L,FALSE +TRUE,6,TextUnit_Line,-1,docEnd,docEnd,-1,docEndM1L,docEndM1L,FALSE +TRUE,6,TextUnit_Line,0,docEnd,docEnd,0,docEnd,docEnd,FALSE +TRUE,6,TextUnit_Line,1,docEnd,docEnd,0,docEnd,docEnd,FALSE +TRUE,6,TextUnit_Line,5,docEnd,docEnd,0,docEnd,docEnd,FALSE +FALSE,6,TextUnit_Line,-5,docEnd,docEndP1C,-5,docEndM5L,docEndM5L,FALSE +FALSE,6,TextUnit_Line,-1,docEnd,docEndP1C,-1,docEndM1L,docEndM1L,FALSE +FALSE,6,TextUnit_Line,0,docEnd,docEndP1C,0,docEnd,docEnd,FALSE +FALSE,6,TextUnit_Line,1,docEnd,docEndP1C,0,docEnd,docEnd,FALSE +FALSE,6,TextUnit_Line,5,docEnd,docEndP1C,0,docEnd,docEnd,FALSE +TRUE,6,TextUnit_Document,-5,docEnd,docEnd,-1,origin,origin,FALSE +TRUE,6,TextUnit_Document,-1,docEnd,docEnd,-1,origin,origin,FALSE +TRUE,6,TextUnit_Document,0,docEnd,docEnd,0,docEnd,docEnd,FALSE +TRUE,6,TextUnit_Document,1,docEnd,docEnd,0,docEnd,docEnd,FALSE +TRUE,6,TextUnit_Document,5,docEnd,docEnd,0,docEnd,docEnd,FALSE +FALSE,6,TextUnit_Document,-5,docEnd,docEndP1C,-1,origin,origin,FALSE +FALSE,6,TextUnit_Document,-1,docEnd,docEndP1C,-1,origin,origin,FALSE +FALSE,6,TextUnit_Document,0,docEnd,docEndP1C,0,docEnd,docEnd,FALSE +FALSE,6,TextUnit_Document,1,docEnd,docEndP1C,0,docEnd,docEnd,FALSE +FALSE,6,TextUnit_Document,5,docEnd,docEndP1C,0,docEnd,docEnd,FALSE +TRUE,7,TextUnit_Character,-5,midEmptySpace,midEmptySpace,-5,docEndM5C,docEndM5C,FALSE +TRUE,7,TextUnit_Character,-1,midEmptySpace,midEmptySpace,-1,docEndM1C,docEndM1C,FALSE +TRUE,7,TextUnit_Character,0,midEmptySpace,midEmptySpace,0,docEnd,docEnd,FALSE +TRUE,7,TextUnit_Character,1,midEmptySpace,midEmptySpace,0,docEnd,docEnd,FALSE +TRUE,7,TextUnit_Character,5,midEmptySpace,midEmptySpace,0,docEnd,docEnd,FALSE +FALSE,7,TextUnit_Character,-5,midEmptySpace,midEmptySpaceP1C,-5,docEndM5C,docEndM5C,FALSE +FALSE,7,TextUnit_Character,-1,midEmptySpace,midEmptySpaceP1C,-1,docEndM1C,docEndM1C,FALSE +FALSE,7,TextUnit_Character,0,midEmptySpace,midEmptySpaceP1C,0,docEnd,docEnd,FALSE +FALSE,7,TextUnit_Character,1,midEmptySpace,midEmptySpaceP1C,0,docEnd,docEnd,FALSE +FALSE,7,TextUnit_Character,5,midEmptySpace,midEmptySpaceP1C,0,docEnd,docEnd,FALSE +TRUE,7,TextUnit_Line,-5,midEmptySpace,midEmptySpace,-5,docEndM5L,docEndM5L,FALSE +TRUE,7,TextUnit_Line,-1,midEmptySpace,midEmptySpace,-1,docEndM1L,docEndM1L,FALSE +TRUE,7,TextUnit_Line,0,midEmptySpace,midEmptySpace,0,docEnd,docEnd,FALSE +TRUE,7,TextUnit_Line,1,midEmptySpace,midEmptySpace,0,docEnd,docEnd,FALSE +TRUE,7,TextUnit_Line,5,midEmptySpace,midEmptySpace,0,docEnd,docEnd,FALSE +FALSE,7,TextUnit_Line,-5,midEmptySpace,midEmptySpaceP1C,-5,docEndM5L,docEndM5L,FALSE +FALSE,7,TextUnit_Line,-1,midEmptySpace,midEmptySpaceP1C,-1,docEndM1L,docEndM1L,FALSE +FALSE,7,TextUnit_Line,0,midEmptySpace,midEmptySpaceP1C,0,docEnd,docEnd,FALSE +FALSE,7,TextUnit_Line,1,midEmptySpace,midEmptySpaceP1C,0,docEnd,docEnd,FALSE +FALSE,7,TextUnit_Line,5,midEmptySpace,midEmptySpaceP1C,0,docEnd,docEnd,FALSE +TRUE,7,TextUnit_Document,-5,midEmptySpace,midEmptySpace,-1,origin,origin,FALSE +TRUE,7,TextUnit_Document,-1,midEmptySpace,midEmptySpace,-1,origin,origin,FALSE +TRUE,7,TextUnit_Document,0,midEmptySpace,midEmptySpace,0,docEnd,docEnd,FALSE +TRUE,7,TextUnit_Document,1,midEmptySpace,midEmptySpace,0,docEnd,docEnd,FALSE +TRUE,7,TextUnit_Document,5,midEmptySpace,midEmptySpace,0,docEnd,docEnd,FALSE +FALSE,7,TextUnit_Document,-5,midEmptySpace,midEmptySpaceP1C,-1,origin,origin,FALSE +FALSE,7,TextUnit_Document,-1,midEmptySpace,midEmptySpaceP1C,-1,origin,origin,FALSE +FALSE,7,TextUnit_Document,0,midEmptySpace,midEmptySpaceP1C,0,docEnd,docEnd,FALSE +FALSE,7,TextUnit_Document,1,midEmptySpace,midEmptySpaceP1C,0,docEnd,docEnd,FALSE +FALSE,7,TextUnit_Document,5,midEmptySpace,midEmptySpaceP1C,0,docEnd,docEnd,FALSE +TRUE,1,TextUnit_Word,-5,origin,origin,0,origin,origin,FALSE +TRUE,1,TextUnit_Word,-1,origin,origin,0,origin,origin,FALSE +TRUE,1,TextUnit_Word,0,origin,origin,0,origin,origin,FALSE +TRUE,1,TextUnit_Word,1,origin,origin,1,segment1LmidTop,segment1LmidTop,FALSE +TRUE,1,TextUnit_Word,5,origin,origin,5,segment0LmidTopP1L,segment0LmidTopP1L,FALSE +FALSE,1,TextUnit_Word,-5,origin,originP1C,0,origin,segment1LmidTop,FALSE +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,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 +FALSE,2,TextUnit_Word,-5,midTop,midTopP1C,-2,origin,segment1LmidTop,FALSE +FALSE,2,TextUnit_Word,-1,midTop,midTopP1C,-1,segment1LmidTop,segment2LmidTop,FALSE +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,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,-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,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,-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,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 +FALSE,5,TextUnit_Word,-5,lastCharPos,lastCharPosP1C,-5,segment4LlastCharPosM1L,lastCharPosLeft,FALSE +FALSE,5,TextUnit_Word,-1,lastCharPos,lastCharPosP1C,-1,segment3LmidDocEnd,segment4LmidDocEnd,FALSE +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,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,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,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,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,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,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,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