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

Code before:
        // 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)
        {
            if (textData.size() >= maxLength)
            {
                // early exit; we're already at/past max length
                break;
            }
            textData += text;
        }
    }

    // - size_t(-1) gets converted to 0xffff...
    // - if the maxLength is more than what we have,
    //     they probably just want the whole thing (so don't resize)
    if (const auto s = gsl::narrow_cast<size_t>(maxLength); s < textData.size())
    {
        textData.resize(s);
    }

    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.

Review comment (suggestion):
I legitimately think that you could (should?) rework the text append loop to not ever append more text than the user requests. After all, why should we copy in a bunch of data that we're just going to delete?

(e.g. If the width is 120, and maxLength is 121... you're going to loop twice:

```
Append 120.
Append 120.
Exit loop.
Truncate from 240 to 121.
```

Why copy the extra 119 characters?
)

Code after:
        // 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();
    });
    RETURN_HR_IF(E_FAIL, !_pData->IsUiaDataInitialized());

    // We can abstract this movement by moving _start