Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Account for viewport movement when wrapping over multiple rows #17353

Merged
merged 2 commits into from
Jun 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions src/host/ut_host/ScreenBufferTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ class ScreenBufferTests
TEST_METHOD(CopyDoubleWidthRectangularArea);

TEST_METHOD(DelayedWrapReset);
TEST_METHOD(MultilineWrap);

TEST_METHOD(EraseColorMode);

Expand Down Expand Up @@ -8323,6 +8324,39 @@ void ScreenBufferTests::DelayedWrapReset()
}
}

void ScreenBufferTests::MultilineWrap()
{
auto& gci = ServiceLocator::LocateGlobals().getConsoleInformation();
auto& si = gci.GetActiveOutputBuffer().GetActiveBuffer();
auto& stateMachine = si.GetStateMachine();
const auto bufferAttr = si.GetTextBuffer().GetCurrentAttributes();
const auto width = si.GetTextBuffer().GetSize().Width();
const auto bottomRow = si.GetViewport().BottomInclusive();

// Starting on the bottom row.
si.GetTextBuffer().GetCursor().SetPosition({ 0, bottomRow });

// Write out enough text to wrap over four lines.
auto fourLines = std::wstring{};
fourLines += L"1";
fourLines += std::wstring(width - 1, L' ');
fourLines += L"2";
fourLines += std::wstring(width - 1, L' ');
fourLines += L"3";
fourLines += std::wstring(width - 1, L' ');
fourLines += L"4";
stateMachine.ProcessString(fourLines);

Log::Comment(L"Cursor should have moved down three rows");
VERIFY_ARE_EQUAL(bottomRow + 3, si.GetTextBuffer().GetCursor().GetPosition().y);

Log::Comment(L"Bottom four rows should have the content 1, 2, 3, and 4");
VERIFY_IS_TRUE(_ValidateLineContains(bottomRow + 0, L"1", bufferAttr));
VERIFY_IS_TRUE(_ValidateLineContains(bottomRow + 1, L"2", bufferAttr));
VERIFY_IS_TRUE(_ValidateLineContains(bottomRow + 2, L"3", bufferAttr));
VERIFY_IS_TRUE(_ValidateLineContains(bottomRow + 3, L"4", bufferAttr));
}

void ScreenBufferTests::EraseColorMode()
{
BEGIN_TEST_METHOD_PROPERTIES()
Expand Down
6 changes: 6 additions & 0 deletions src/terminal/adapter/PageManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,12 @@ til::CoordType Page::YPanOffset() const noexcept
return 0; // Vertical panning is not yet supported
}

void Page::MoveViewportDown() noexcept
{
_viewport.top++;
_viewport.bottom++;
}

PageManager::PageManager(ITerminalApi& api, Renderer& renderer) noexcept :
_api{ api },
_renderer{ renderer }
Expand Down
1 change: 1 addition & 0 deletions src/terminal/adapter/PageManager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ namespace Microsoft::Console::VirtualTerminal
til::CoordType BufferHeight() const noexcept;
til::CoordType XPanOffset() const noexcept;
til::CoordType YPanOffset() const noexcept;
void MoveViewportDown() noexcept;

private:
TextBuffer& _buffer;
Expand Down
20 changes: 15 additions & 5 deletions src/terminal/adapter/adaptDispatch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,14 @@ void AdaptDispatch::PrintString(const std::wstring_view string)

void AdaptDispatch::_WriteToBuffer(const std::wstring_view string)
{
const auto page = _pages.ActivePage();
auto page = _pages.ActivePage();
auto& textBuffer = page.Buffer();
auto& cursor = page.Cursor();
auto cursorPosition = cursor.GetPosition();
const auto wrapAtEOL = _api.GetSystemMode(ITerminalApi::Mode::AutoWrap);
const auto& attributes = page.Attributes();

const auto [topMargin, bottomMargin] = _GetVerticalMargins(page, true);
auto [topMargin, bottomMargin] = _GetVerticalMargins(page, true);
const auto [leftMargin, rightMargin] = _GetHorizontalMargins(page.Width());

auto lineWidth = textBuffer.GetLineWidth(cursorPosition.y);
Expand All @@ -107,7 +107,14 @@ void AdaptDispatch::_WriteToBuffer(const std::wstring_view string)
// different position from where the EOL was marked.
if (delayedCursorPosition == cursorPosition)
{
_DoLineFeed(page, true, true);
if (_DoLineFeed(page, true, true))
{
// If the line feed caused the viewport to move down, we
// need to adjust the page viewport and margins to match.
page.MoveViewportDown();
std::tie(topMargin, bottomMargin) = _GetVerticalMargins(page, true);
}

cursorPosition = cursor.GetPosition();
// We need to recalculate the width when moving to a new line.
lineWidth = textBuffer.GetLineWidth(cursorPosition.y);
Expand Down Expand Up @@ -2505,14 +2512,15 @@ bool AdaptDispatch::CarriageReturn()
// - withReturn - Set to true if a carriage return should be performed as well.
// - wrapForced - Set to true is the line feed was the result of the line wrapping.
// Return Value:
// - <none>
void AdaptDispatch::_DoLineFeed(const Page& page, const bool withReturn, const bool wrapForced)
// - True if the viewport panned down. False if not.
bool AdaptDispatch::_DoLineFeed(const Page& page, const bool withReturn, const bool wrapForced)
{
auto& textBuffer = page.Buffer();
const auto pageWidth = page.Width();
const auto bufferHeight = page.BufferHeight();
const auto [topMargin, bottomMargin] = _GetVerticalMargins(page, true);
const auto [leftMargin, rightMargin] = _GetHorizontalMargins(pageWidth);
auto viewportMoved = false;

auto& cursor = page.Cursor();
const auto currentPosition = cursor.GetPosition();
Expand Down Expand Up @@ -2555,6 +2563,7 @@ void AdaptDispatch::_DoLineFeed(const Page& page, const bool withReturn, const b
// the end of the buffer.
_api.SetViewportPosition({ page.XPanOffset(), page.Top() + 1 });
newPosition.y++;
viewportMoved = true;

// And if the bottom margin didn't cover the full page, we copy the
// lower part of the page down so it remains static. But for a full
Expand Down Expand Up @@ -2594,6 +2603,7 @@ void AdaptDispatch::_DoLineFeed(const Page& page, const bool withReturn, const b

cursor.SetPosition(newPosition);
_ApplyCursorMovementFlags(cursor);
return viewportMoved;
}

// Routine Description:
Expand Down
2 changes: 1 addition & 1 deletion src/terminal/adapter/adaptDispatch.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ namespace Microsoft::Console::VirtualTerminal
const VTInt rightMargin,
const bool homeCursor = false);

void _DoLineFeed(const Page& page, const bool withReturn, const bool wrapForced);
bool _DoLineFeed(const Page& page, const bool withReturn, const bool wrapForced);

void _DeviceStatusReport(const wchar_t* parameters) const;
void _CursorPositionReport(const bool extendedReport);
Expand Down
Loading