-
Notifications
You must be signed in to change notification settings - Fork 9.1k
Description
Environment
Windows build number: Version 10.0.18362.175
Windows Terminal version (if applicable): Commit a08666b
It has to be a build that includes PR #1807, otherwise the scrolling probably wouldn't work at all.
Steps to reproduce
The issue manifests in a number of different ways, but one of the most obvious examples looks like this:
-
Start the conhost: Host.exe
-
In the properties, make sure that the Screen Buffer Height is larger than the Window Height.
-
Open a WSL bash shell.
-
Get a directory listing, or something that fills the screen with content.
-
Execute the following escape sequence, which sets the background color to red, and deletes 4 lines from the top of the screen:
printf "\e[41m\e[H\e[4M"
Expected behavior
The contents of the window should scroll up by 4 lines, revealing 4 blank red lines at the bottom of the screen.
Actual behavior
The blank lines are black rather than red. However, if you scroll down to the very end of the buffer, you'll see the 4 red lines there instead.
I believe the problem is that the call to ScrollRegion should have been passed a clip rect matching the window/viewport, but instead was given a rect encompassing the full buffer size.
In this case, the offending code is in the DoSrvPrivateModifyLinesImpl function, which calls the ScrollRegion function via the ScrollConsoleScreenBufferWImpl method:
Lines 2055 to 2063 in 0e6f290
| SMALL_RECT srClip = screenEdges; | |
| srClip.Top = cursorPosition.Y; | |
| LOG_IF_FAILED(ServiceLocator::LocateGlobals().api.ScrollConsoleScreenBufferWImpl(screenInfo, | |
| srScroll, | |
| coordDestination, | |
| srClip, | |
| UNICODE_SPACE, | |
| screenInfo.GetAttributes().GetLegacyAttributes())); |
The screenEdges rect (with which the srClip rect is initialised), is set here:
Line 2036 in 0e6f290
| const auto screenEdges = screenInfo.GetBufferSize().ToInclusive(); |
Additional examples
The IL (insert lines) escape sequence is similarly affected. When you insert lines onto the screen, anything that scrolls off the bottom of the viewport should be lost, but it's actually just scrolled into the forward buffer, so if you scroll down you can still see it.
For example, execute the sequence below, and then scroll the viewport down to reveal the LAST LINE text that was shifted off screen (it should have been erased):
printf "\e[100BLAST LINE\e[H\e[4L"
The SU (scroll up) and SD (scroll down) escape sequences almost get it right. They're using the viewport as their clip rect, but they're using an exclusive range, where the ScrollRegion function expects an inclusive range, so they're off by one.
For example, if you fill the screen with content as with the first test case, then execute the following escape sequence, which scrolls up by 4 lines:
printf "\e[41m\e[H\e[4S"
That should reveal 4 blank red lines at the bottom of the screen, but actually only 3 of them are red - the fourth red line is off screen.
So far the only command I've found that gets the clip rect correct is the RI (reverse index) sequence.