Fix viewport moving when we've scrolled up and circled the buffer (#7247)
If you scroll up to view the scrollback, then we want the viewport to "stay in place", as new output comes in (see #6062). This works fine up until the buffer circles. In this case, the mutable viewport isn't actually moving, so we never set `updatedViewport` to true. This regressed in #6062 Closes #7222
This commit is contained in:
parent
7ccd1f6f1a
commit
bc642bbf2a
|
@ -843,8 +843,12 @@ void Terminal::_AdjustCursorPosition(const COORD proposedPosition)
|
|||
}
|
||||
}
|
||||
|
||||
if (updatedViewport)
|
||||
// If the viewport moved, or we circled the buffer, we might need to update
|
||||
// our _scrollOffset
|
||||
if (updatedViewport || newRows != 0)
|
||||
{
|
||||
const auto oldScrollOffset = _scrollOffset;
|
||||
|
||||
// scroll if...
|
||||
// - no selection is active
|
||||
// - viewport is already at the bottom
|
||||
|
@ -852,6 +856,18 @@ void Terminal::_AdjustCursorPosition(const COORD proposedPosition)
|
|||
|
||||
_scrollOffset = scrollToOutput ? 0 : _scrollOffset + scrollAmount + newRows;
|
||||
|
||||
// Clamp the range to make sure that we don't scroll way off the top of the buffer
|
||||
_scrollOffset = std::clamp(_scrollOffset,
|
||||
0,
|
||||
_buffer->GetSize().Height() - _mutableViewport.Height());
|
||||
|
||||
// If the new scroll offset is different, then we'll still want to raise a scroll event
|
||||
updatedViewport = updatedViewport || (oldScrollOffset != _scrollOffset);
|
||||
}
|
||||
|
||||
// If the viewport moved, then send a scrolling notification.
|
||||
if (updatedViewport)
|
||||
{
|
||||
_NotifyScrollEvent();
|
||||
}
|
||||
|
||||
|
|
|
@ -39,6 +39,8 @@ class TerminalCoreUnitTests::TerminalBufferTests final
|
|||
TEST_METHOD(TestWrappingCharByChar);
|
||||
TEST_METHOD(TestWrappingALongString);
|
||||
|
||||
TEST_METHOD(DontSnapToOutputTest);
|
||||
|
||||
TEST_METHOD_SETUP(MethodSetup)
|
||||
{
|
||||
// STEP 1: Set up the Terminal
|
||||
|
@ -149,3 +151,85 @@ void TerminalBufferTests::TestWrappingALongString()
|
|||
|
||||
TestUtils::VerifyExpectedString(termTb, TestUtils::Test100CharsString, { 0, 0 });
|
||||
}
|
||||
|
||||
void TerminalBufferTests::DontSnapToOutputTest()
|
||||
{
|
||||
auto& termTb = *term->_buffer;
|
||||
auto& termSm = *term->_stateMachine;
|
||||
const auto initialView = term->GetViewport();
|
||||
|
||||
VERIFY_ARE_EQUAL(0, initialView.Top());
|
||||
VERIFY_ARE_EQUAL(TerminalViewHeight, initialView.BottomExclusive());
|
||||
VERIFY_ARE_EQUAL(0, term->_scrollOffset);
|
||||
|
||||
// -1 so that we don't print the last \n
|
||||
for (int i = 0; i < TerminalViewHeight + 8 - 1; i++)
|
||||
{
|
||||
termSm.ProcessString(L"x\n");
|
||||
}
|
||||
|
||||
const auto secondView = term->GetViewport();
|
||||
|
||||
VERIFY_ARE_EQUAL(8, secondView.Top());
|
||||
VERIFY_ARE_EQUAL(TerminalViewHeight + 8, secondView.BottomExclusive());
|
||||
VERIFY_ARE_EQUAL(0, term->_scrollOffset);
|
||||
|
||||
Log::Comment(L"Scroll up one line");
|
||||
term->_scrollOffset = 1;
|
||||
|
||||
const auto thirdView = term->GetViewport();
|
||||
VERIFY_ARE_EQUAL(7, thirdView.Top());
|
||||
VERIFY_ARE_EQUAL(TerminalViewHeight + 7, thirdView.BottomExclusive());
|
||||
VERIFY_ARE_EQUAL(1, term->_scrollOffset);
|
||||
|
||||
Log::Comment(L"Print a few lines, to see that the viewport stays where it was");
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
termSm.ProcessString(L"x\n");
|
||||
}
|
||||
|
||||
const auto fourthView = term->GetViewport();
|
||||
VERIFY_ARE_EQUAL(7, fourthView.Top());
|
||||
VERIFY_ARE_EQUAL(TerminalViewHeight + 7, fourthView.BottomExclusive());
|
||||
VERIFY_ARE_EQUAL(1 + 8, term->_scrollOffset);
|
||||
|
||||
Log::Comment(L"Print enough lines to get the buffer just about ready to "
|
||||
L"circle (on the next newline)");
|
||||
auto viewBottom = term->_mutableViewport.BottomInclusive();
|
||||
do
|
||||
{
|
||||
termSm.ProcessString(L"x\n");
|
||||
viewBottom = term->_mutableViewport.BottomInclusive();
|
||||
} while (viewBottom < termTb.GetSize().BottomInclusive());
|
||||
|
||||
const auto fifthView = term->GetViewport();
|
||||
VERIFY_ARE_EQUAL(7, fifthView.Top());
|
||||
VERIFY_ARE_EQUAL(TerminalViewHeight + 7, fifthView.BottomExclusive());
|
||||
VERIFY_ARE_EQUAL(TerminalHistoryLength - 7, term->_scrollOffset);
|
||||
|
||||
Log::Comment(L"Print 3 more lines, and see that we stick to where the old "
|
||||
L"rows now are in the buffer (after circling)");
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
termSm.ProcessString(L"x\n");
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"_scrollOffset: %d", term->_scrollOffset));
|
||||
}
|
||||
const auto sixthView = term->GetViewport();
|
||||
VERIFY_ARE_EQUAL(4, sixthView.Top());
|
||||
VERIFY_ARE_EQUAL(TerminalViewHeight + 4, sixthView.BottomExclusive());
|
||||
VERIFY_ARE_EQUAL(TerminalHistoryLength - 4, term->_scrollOffset);
|
||||
|
||||
Log::Comment(L"Print 8 more lines, and see that we're now just stuck at the"
|
||||
L"top of the buffer");
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
termSm.ProcessString(L"x\n");
|
||||
Log::Comment(NoThrowString().Format(
|
||||
L"_scrollOffset: %d", term->_scrollOffset));
|
||||
}
|
||||
const auto seventhView = term->GetViewport();
|
||||
VERIFY_ARE_EQUAL(0, seventhView.Top());
|
||||
VERIFY_ARE_EQUAL(TerminalViewHeight, seventhView.BottomExclusive());
|
||||
VERIFY_ARE_EQUAL(TerminalHistoryLength, term->_scrollOffset);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue