Repository: microsoft/terminal
File: src/cascadia/TerminalCore/Terminal.cpp (C++)

Code before:
            // GetInputDistance() thus returns 0, which would in turn cause i to be
            // decremented by 1 below and force the outer loop to loop forever.
            // This if() basically behaves as if "\r\n" had been encountered above and retries the write.
            // With well behaving shells during normal operation this safeguard should normally not be encountered.
            proposedCursorPosition.X = 0;
            proposedCursorPosition.Y++;

            // Try the character again.
            i--;

            // If we write the last cell of the row here, TextBuffer::Write will
            // mark this line as wrapped for us. If the next character we
            // process is a newline, the Terminal::CursorLineFeed will unmark
            // this line as wrapped.

            // TODO: GH#780 - This should really be a _deferred_ newline. If
            // the next character to come in is a newline or a cursor
            // movement or anything, then we should _not_ wrap this line
            // here.
        }

        _AdjustCursorPosition(proposedCursorPosition);
    }

    cursor.EndDeferDrawing();
    _NotifyTerminalCursorPositionChanged();
}

void Terminal::_AdjustCursorPosition(const COORD proposedPosition)
{
#pragma warning(suppress : 26496) // cpp core checks wants this const but it's modified below.
    auto proposedCursorPosition = proposedPosition;
    auto& cursor = _buffer->GetCursor();
    const Viewport bufferSize = _buffer->GetSize();

    // If we're about to scroll past the bottom of the buffer, instead cycle the
    // buffer.
    SHORT rowsPushedOffTopOfBuffer = 0;
    const auto newRows = std::max(0, proposedCursorPosition.Y - bufferSize.Height() + 1);
    if (proposedCursorPosition.Y >= bufferSize.Height())
    {
        for (auto dy = 0; dy < newRows; dy++)
        {
            _buffer->IncrementCircularBuffer();
            proposedCursorPosition.Y--;
            rowsPushedOffTopOfBuffer++;

            // Update our selection too, so it doesn't move as the buffer is cycled
            if (_selection)
            {
                // If the start of the selection is above 0, we can reduce both the start and end by 1

Review comment (suggestion):
If we do it like that, I believe it's easier to understand if you remove the call to `_NotifyTerminalCursorPositionChanged` from `_AdjustCursorPosition` entirely and instead add it at the end of `CursorLineFeed`.

That way both functions have the exact same "code structure" of calling `_NotifyTerminalCursorPositionChanged` at the end. This would feel more consistent and logical to me.

Code after:
        const auto cellDistance = end.GetCellDistance(it);
        const auto inputDistance = end.GetInputDistance(it);

        if (inputDistance > 0)
        {
            // If "wch" was a surrogate character, we just consumed 2 code units above.
            // -> Increment "i" by 1 in that case and thus by 2 in total in this iteration.
            proposedCursorPosition.X += gsl::narrow<SHORT>(cellDistance);
            i += inputDistance - 1;
        }
        else
        {
            // If _WriteBuffer() is called with a consecutive string longer than the viewport/buffer width
            // the call to _buffer->Write() will refuse to write anything on the current line.
            // GetInputDistance() thus returns 0, which would in turn cause i to be
            // decremented by 1 below and force the outer loop to loop forever.
            // This if() basically behaves as if "\r\n" had been encountered above and retries the write.
            // With well behaving shells during normal operation this safeguard should normally not be encountered.
            proposedCursorPosition.X = 0;
            proposedCursorPosition.Y++;

            // Try the character again.
            i--;

            // If we write the last cell of the row here, TextBuffer::Write will
            // mark this line as wrapped for us. If the next character we
            // process is a newline, the Terminal::CursorLineFeed will unmark
            // this line as wrapped.

            // TODO: GH#780 - This should really be a _deferred_ newline. If
            // the next character to come in is a newline or a cursor
            // movement or anything, then we should _not_ wrap this line
            // here.
        }

        _AdjustCursorPosition(proposedCursorPosition);
    }

    cursor.EndDeferDrawing();
}

void Terminal::_AdjustCursorPosition(const COORD proposedPosition)
{
#pragma warning(suppress : 26496) // cpp core checks wants this const but it's modified below.
    auto proposedCursorPosition = proposedPosition;
    auto& cursor = _buffer->GetCursor();
    const Viewport bufferSize = _buffer->GetSize();

    // If we're about to scroll past the bottom of the buffer, instead cycle the
    // buffer.
    SHORT rowsPushedOffTopOfBuffer = 0;