-
Notifications
You must be signed in to change notification settings - Fork 8.5k
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
Regression in scrolled-forward invalidation behavior from #4171 0586955c88fac8c6f631b89a8b19d4338bfa26ad #5302
Comments
The ability to scroll the bottom line of the console up is an atrocity that, unfortunately, thousands of our users apparently love. |
It looks like it's got something to do with the fact that the new carriage return handler makes a I'm still not sure why the |
So, this is probably a bad interaction with our "virtual bottom". In 19H1, we added a mode that disables the atrocity mentioned above (scroll-forward). The "bottom" of the buffer is tracked in |
OK, I think I know what's going on now. When the viewport bottom is below the virtual bottom, the virtual bottom doesn't get updated. So you've got an app writing stuff to an area of the screen that won't be visible once the viewport is forced back to the correct position (which happens with a In earlier versions of the code, this was less of a problem. You might have a VT operation that triggered A bunch of VT things would be broken in these situations, and there were still a couple of cases where the viewport would not correct its position, but that was less common. Once I refactored the cursor movement in PR #3628, things got a lot worse though. Now every cursor movement operation makes sure the position is clamped within the viewport, so it doesn't have the chance to force the viewport back down like it used to. And then PR #4171 made it so every VT carriage return could trigger the issue, and that's going to happen every time the command prompt is output. The bottom line is I think this has been broken for a long time. It's just that the effects of the issue have been made a lot worse by those two PRs. As for how we fix it, I thought we could possibly just add a check in the Lines 267 to 279 in ef80f66
...we'd add a second condition, with something like this:
That seems to fix the issue for me, but I don't know if that's necessarily the right solution, or that there aren't other places in the code that would require similar updates. |
Another option would be to add the check in the And then the minute you get a VT cursor movement operation, the viewport will suddenly jump down to that position. And with the cmd shell always being in VT mode, that's going to happen as soon as the app exits. But that does seem like a weird edge case, and maybe that is the behaviour you would expect in that situation. And possibly half the problem is we're doing |
After further investigation, I've decided this really isn't a problem. The |
If an application writes to the screen while not in VT mode, and the user has scrolled forward in the screen buffer, the _virtual bottom_ location is not updated to take that new content into account. As a result, the viewport can later jump back to the previous _virtual bottom_, making the content disappear off screen. This PR attempts to fix that issue by updating the _virtual bottom_ location whenever the cursor moves below that point. ## PR Checklist * [x] CLA signed. * [x] Tests added/passed ## Detailed Description of the Pull Request / Additional comments This simply adds a condition in the `SCREEN_INFORMATION::SetCursorPosition` to check if the new _Y_ coordinate is below the current _virtual bottom_, and if so, updates the _virtual bottom_ to that new value. I considered trying to make it only update when something is actually written to the screen, but this seemed like a cleaner solution, and is less likely to miss out on a needed update. ## Validation Steps Performed I've manually tested the case described in issue #5302, and confirmed that it now works as expected. I've also added a unit test that checks the virtual bottom is updated correctly under similar conditions. Closes #5302
The "virtual bottom" marks the last line of the mutable viewport area, which is the part of the buffer that VT sequences can write to. This region should typically only move downwards as new lines are added to the buffer, but there were a number of cases where it was incorrectly being moved up, or moved down further than necessary. This PR attempts to fix that. There was an earlier, unsuccessful attempt to fix this in PR #9770 which was later reverted (issue #9872 was the reason it had to be reverted). PRs #2666, #2705, and #5317 were fixes for related virtual viewport problems, some of which have either been extended or superseded by this PR. `SetConsoleCursorPositionImpl` is one of the cases that actually does need to move the virtual viewport upwards sometimes, in particular when the cmd shell resets the buffer with a `CLS` command. But when this operation "snaps" the viewport to the location of the cursor, it needs to use the virtual viewport as the frame of reference. This was partially addressed by PR #2705, but that only applied in terminal-scrolling mode, so I've now applied that fix regardless of the mode. `SetViewportOrigin` takes a flag which determines whether it will also move the virtual bottom to match the visible viewport. In some case this is appropriate (`SetConsoleCursorPositionImpl` being one example), but in other cases (e.g. when panning the viewport downwards in the `AdjustCursorPosition` function), it should only be allowed to move downwards. We can't just not set the update flag in those cases, because that also determines whether or not the viewport would be clamped, and we don't want change that. So what I've done is limit `SetViewportOrigin` to only move the virtual bottom downwards, and added an explicit `UpdateBottom` call in those places that may also require upward movement. `ResizeWindow` in the `ConhostInternalGetSet` class has a similar problem to `SetConsoleCursorPositionImpl`, in that it's updating the viewport to account for the new size, but if that visible viewport is scrolled back or forward, it would end up placing the virtual viewport in the wrong place. So again the solution here was to use the virtual viewport as the frame of reference for the position. However, if the viewport is being shrunk, this can still result in the cursor falling below the bottom, so we need an additional check to adjust for that. This can't be applied in pty mode, though, because that would break the conpty resizing operation. `_InternalSetViewportSize` comes into play when resizing the window manually, and again the viewport after the resize can end up truncating the virtual bottom if not handled correctly. This was partially addressed in the original code by clamping the new viewport above the virtual bottom under certain conditions, and only in terminal scrolling mode. I've replaced that with a new algorithm which links the virtual bottom to the visible viewport bottom if the two intersect, but otherwise leaves it unchanged. This applies regardless of the scrolling mode. `ResizeWithReflow` is another sizing operation that can affect the virtual bottom. This occurs when a change of the window width requires the buffer to be reflowed, and we need to reposition the viewport in the newly generated buffer. Previously we were just setting the virtual bottom to align with the new visible viewport, but that could easily result in the buffer truncation if the visible viewport was scrolled back at the time. We now set the virtual bottom to the last non-space row, or the cursor row (whichever is larger). There'll be edge cases where this is probably not ideal, but it should still work reasonably well. `MakeCursorVisible` was another case where the virtual bottom was being updated (when requested with a flag) via a `SetViewportOrigin` call. When I checked all the places it was used, though, none of them actually required that behavior, and doing so could result in the virtual bottom being incorrectly positioned, even after `SetViewportOrigin` was limited to moving the virtual bottom downwards. So I've now made it so that `MakeCursorVisible` never updates the virtual bottom. `SelectAll` in the `Selection` class was a similar case. It was calling `SetViewportOrigin` with the `updateBottom` flag set when that really wasn't necessary and could result in the virtual bottom being incorrectly set. I've changed the flag to false now. ## Validation Steps Performed I've manually confirmed that the test cases in issue #9754 are working now, except for the one involving margins, which is bigger problem with `AdjustCursorPosition` which will need to be addressed separately. I've also double checked the test cases from several other virtual bottom issues (#1206, #1222, #5302, and #9872), and confirmed that they're still working correctly with these changes. And I've added a few screen buffer tests in which I've tried to cover as many of the problematic code paths as possible. Closes #9754
Repro from MSFT:25863049
In an unelevated command prompt window, run "dir" twice to fill up the buffer, scroll down until the prompt is in the middle of the screen, then run "dism"
It should print information below the prompt about how it needs to be run elevated, and then return to a prompt.
Instead, it prints that information at a random location.
Bisect brought me to #4171.
(/cc @j4james)
The text was updated successfully, but these errors were encountered: