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

Code before:
        //   - true: we want the visible viewport to show the new output
        //   - false: keep the visible viewport in its current position
        bool scrollToOutput = true;

        // modify scrollOffset based on SnapOnOutput value
        if (_snapOnOutput == static_cast<int>(SnapOnOutputFlag::Always))
        {
            scrollToOutput = true;
        }
        else if (_snapOnOutput == static_cast<int>(SnapOnOutputFlag::Never))
        {
            scrollToOutput = false;
        }

        // IMPORTANT: we need to use && below. This allows multiple of these flags to be set
        if (WI_IsFlagSet(_snapOnOutput, static_cast<int>(SnapOnOutputFlag::NoSelection)))
        {
            // scroll if no selection is active
            scrollToOutput = scrollToOutput && !IsSelectionActive();
        }
        if (WI_IsFlagSet(_snapOnOutput, static_cast<int>(SnapOnOutputFlag::AtBottom)))
        {
            scrollToOutput = scrollToOutput && viewportAtBottom;
        }

        // use scrollToOutput to enforce SnapOnInput
        _scrollOffset = scrollToOutput ? 0 : _scrollOffset + scrollAmount + newRows;

        // We have to report the delta here because we might have circled the text buffer.
        // That didn't change the viewport and therefore the TriggerScroll(void)
        // method can't detect the delta on its own.
        COORD delta{ 0, -gsl::narrow<SHORT>(newRows) };
        _buffer->GetRenderTarget().TriggerScroll(&delta);

        _NotifyScrollEvent();
    }

    _NotifyTerminalCursorPositionChanged();
}

void Terminal::UserScrollViewport(const int viewTop)
{
    // we're going to modify state here that the renderer could be reading.
    auto lock = LockForWriting();

    const auto clampedNewTop = std::max(0, viewTop);
    const auto realTop = ViewStartIndex();
    const auto newDelta = realTop - clampedNewTop;
    // if viewTop > realTop, we want the offset to be 0.

    _scrollOffset = std::max(0, newDelta);

Review comment (suggestion):
```suggestion
        // use scrollToOutput to enforce SnapOnOutput
```

Code after:
    const auto scrollAmount = std::max(0, proposedCursorPosition.Y - _mutableViewport.BottomInclusive());
    if (scrollAmount > 0)
    {
        const auto newViewTop = std::max(0, proposedCursorPosition.Y - (_mutableViewport.Height() - 1));
        if (newViewTop != _mutableViewport.Top())
        {
            _mutableViewport = Viewport::FromDimensions({ 0, gsl::narrow<short>(newViewTop) },
                                                        _mutableViewport.Dimensions());
            updatedViewport = true;
        }
    }

    if (updatedViewport)
    {
        // scroll if...
        //   - no selection is active
        //   - viewport is already at the bottom
        const bool scrollToOutput = !IsSelectionActive() && _scrollOffset == 0;

        _scrollOffset = scrollToOutput ? 0 : _scrollOffset + scrollAmount + newRows;

        _NotifyScrollEvent();
    }

    if (rowsPushedOffTopOfBuffer != 0)
    {
        // We have to report the delta here because we might have circled the text buffer.
        // That didn't change the viewport and therefore the TriggerScroll(void)
        // method can't detect the delta on its own.
        COORD delta{ 0, -rowsPushedOffTopOfBuffer };
        _buffer->GetRenderTarget().TriggerScroll(&delta);
    }

    _NotifyTerminalCursorPositionChanged();
}

void Terminal::UserScrollViewport(const int viewTop)
{
    // we're going to modify state here that the renderer could be reading.
    auto lock = LockForWriting();

    const auto clampedNewTop = std::max(0, viewTop);
    const auto realTop = ViewStartIndex();
    const auto newDelta = realTop - clampedNewTop;
    // if viewTop > realTop, we want the offset to be 0.

    _scrollOffset = std::max(0, newDelta);

    // We can use the void variant of TriggerScroll here because
    // we adjusted the viewport so it can detect the difference
    // from the previous frame drawn.