Repository: microsoft/terminal
File: src/types/UiaTextRangeBase.cpp (C++)

Code before:
        // otherwise, we'll FailFast catastrophically
        THROW_HR_IF(E_FAIL, !bufferSize.IsInBounds(_start) || !bufferSize.IsInBounds(_end));

        // convert _end to be inclusive
        auto inclusiveEnd = _end;
        bufferSize.DecrementInBounds(inclusiveEnd, true);

        const auto textRects = buffer.GetTextRects(_start, inclusiveEnd, _blockRange, true);
        const auto bufferData = buffer.GetText(true,
                                               false,
                                               textRects);

        const size_t textDataSize = bufferData.text.size() * bufferSize.Width();
        textData.reserve(textDataSize);
        for (const auto& text : bufferData.text)
        {
            textData += text;
        }
    }

    // if the caller asked for INT_MAX,
    // they probably just want the whole thing
    if (maxLength >= 0 && maxLength != INT_MAX)
    {
        textData.resize(maxLength);
    }

    return textData;
}
#pragma warning(pop)

IFACEMETHODIMP UiaTextRangeBase::Move(_In_ TextUnit unit,
                                      _In_ int count,
                                      _Out_ int* pRetVal) noexcept
try
{
    RETURN_HR_IF(E_INVALIDARG, pRetVal == nullptr);
    *pRetVal = 0;

    _pData->LockConsole();
    auto Unlock = wil::scope_exit([&]() noexcept {
        _pData->UnlockConsole();
    });
    RETURN_HR_IF(E_FAIL, !_pData->IsUiaDataInitialized());

    // 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 auto documentEnd = _getDocumentEnd();

Review comment (bug):
@carlos-zamora Correct me if I'm wrong, but to me it sounds like we're supposed to only shrink the string... But `resize()` with a `maxLength` greater than the string length pads it with `L'\0'`s at the end. Do we want that? Otherwise:

```suggestion
    if (const auto s = gsl::narrow_cast<size_t>(maxLength); s < textData.size())
    {
        textData.resize(s);
    }
```

(Casting `-1` to unsigned results in `0xffff...`.)

Code after:
        const auto maxLengthAsSize = gsl::narrow_cast<size_t>(maxLength);

        // TODO GH#5406: create a different UIA parent object for each TextBuffer
        // nvaccess/nvda#11428: Ensure our endpoints are in bounds
        THROW_HR_IF(E_FAIL, !bufferSize.IsInBounds(_start) || !bufferSize.IsInBounds(_end));

        // convert _end to be inclusive
        auto inclusiveEnd = _end;
        bufferSize.DecrementInBounds(inclusiveEnd, true);

        // reserve size in accordance to extracted text
        const auto textRects = buffer.GetTextRects(_start, inclusiveEnd, _blockRange, true);
        const auto bufferData = buffer.GetText(true,
                                               false,
                                               textRects);
        const size_t textDataSize = bufferData.text.size() * bufferSize.Width();
        textData.reserve(textDataSize);
        for (const auto& text : bufferData.text)
        {
            if (textData.size() >= maxLengthAsSize)
            {
                // early exit; we're already at/past max length
                break;
            }
            textData += text;
        }

        // only use maxLength to resize down.
        // if maxLength > size, we don't want to resize and append unnecessary L'\0'.
        if (textData.size() > maxLengthAsSize)
        {
            textData.resize(maxLengthAsSize);
        }
    }

    return textData;
}
#pragma warning(pop)

IFACEMETHODIMP UiaTextRangeBase::Move(_In_ TextUnit unit,
                                      _In_ int count,
                                      _Out_ int* pRetVal) noexcept
try
{
    RETURN_HR_IF(E_INVALIDARG, pRetVal == nullptr);
    *pRetVal = 0;

    _pData->LockConsole();
    auto Unlock = wil::scope_exit([&]() noexcept {
        _pData->UnlockConsole();
    });