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

Code before:
            // 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);
    }

    // Notify UIA of new text.
    // It's important to do this here instead of in TextBuffer, because here you have access to the entire line of text,
    // whereas TextBuffer writes it one character at a time via the OutputCellIterator.
    static std::wstring newline{ L"\n" };
    _buffer->GetRenderTarget().TriggerNewTextNotification(std::wstring{ stringView } + newline);

    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;
    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)

Review comment (suggestion):
### Fun fact

Found some interesting behavior here when playing with different shells...
| Shell | Output when you type <kbd>a</kbd> + <kbd>b</kbd> + <kbd>c</kbd> |
|--|--|
| Ubuntu | `a` ... `b` ... `c` |
| PowerShell | `a` ... `ab` ... `abc` |
| PowerShell (disabled PSReadLine) | `a` ... `b` ... `c` |

As shown above, PowerShell actually rewrites the entire input buffer with each keyboard event! Why? Idk. But that made it particularly frustrating when I was trying to suppress the "local echo".

Fortunately, it seems like PowerShell has been aware of this issue for some time, because _if PowerShell detects that you are using a screen reader, it disables PSReadLine_!

So in your local testing, make sure you open your screen reader (or accessibility insights) first, _then_ open a PowerShell instance. That way, PowerShell will detect that you are using a screen reader and disable PSReadLine automatically (as well as output some text saying that it's done just that).

Code after:
            // 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);
    }

    // Notify UIA of new text.
    // It's important to do this here instead of in TextBuffer, because here you have access to the entire line of text,
    // whereas TextBuffer writes it one character at a time via the OutputCellIterator.
    _buffer->GetRenderTarget().TriggerNewTextNotification(stringView);

    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;
    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)
            {