[PR #4354] When the Terminal is resized, don't remove lines from scrollback #25718

Open
opened 2026-01-31 09:11:20 +00:00 by claunia · 0 comments
Owner

Original Pull Request: https://github.com/microsoft/terminal/pull/4354

State: closed
Merged: No


Summary of the Pull Request

This PR fixes a bug in the Windows Terminal, where decreasing the height of the window would cause some lines from the scrollback to be lost. While a seemingly trivial bug, this actually involved some elaborate manipulation of how conpty decides to render a resize operation.

References

PR Checklist

Detailed Description of the Pull Request / Additional comments

Conpty was not emitting the correct thing when you'd decrease the height of the viewport. When you increase the height of the window, we'd both invalidate the entire buffer, and insert new lines to the bottom of the buffer. What this meant is that on every height-only resize, we'd re-emit the entire viewport.

  • If you resized down twice (From R to R-1 to R-2), once during the frame being emitted by conpty, the Terminal would try to process the R-1 lines emitted by conpty when there are only R-2 available rows in the terminal buffer. This would lead to duplicated lines.

This involved a bunch of changes throughout the codebase to make sure we weren't just calling TriggerRedraw on the entire viewport when we resize the buffer. Magically, conpty was pretty good about knowing what actually changed, though that did need some updating as well (in VtEngine::UpdateViewport).

  • Importantly, there's a minor change to ScreenInfo to cause it to only invalidate wrapped lines during a ResizeWithReflow. Previously, we'd be invalidating the entire viewport, but that caused issues terminal-side. It's better to only tell the terminal what actually changed during the reflow.

With those changes, the Terminal was changed to more intelligently stick to the right location in the buffer. When increasing the height of conpty, new lines always get inserted at the bottom of the viewport, so the terminal needs to stick to roughly the old top's position to re-create this stateWhen resizing down, empty lines are clipped from the conpty if there are any, then lines from the top are removed.

This is obviously all very complicated, so I've added some tests to validate all this. ConptyRoundtripTests::TestResizeHeight is elaborate and it does the right thing here, validating the contents of both conpty and the Terminal after emitting various numbers of lines into the buffer and doing arbitrary resizes.

As with any conpty change, I'm horrified that this will break in new and more horrifying ways. I'm hoping that a long bake time will help us identify bugs in this changelist (if there are any).

Validation Steps Performed

In VtPipeTerm and Windows Terminal:

  1. wsl seq 100
  2. resize down - scroll to make sure buffer has the right contents
  3. resize up - scroll to make sure buffer has the right contents
  4. resize down quickly - scroll to make sure buffer has the right contents
  5. resize up quickly - scroll to make sure buffer has the right contents

Additionally, resize quickly from the corner, and ensure ll the lines are right.

Aditionally, perform all the above with less than a full viewport of output.

Aditidionally, after the above tests, perform a sleep 2 ; printf "\e[6n" and quickly hit esc to query the cursors position in conpty, and make sure it lines up with the Terminal's.

Also play with resizing and PSReadline, and all the lovely things PSR does to the cursor.

This was the original PR body I had for this change. It's included here for future code archeologists. It's not really accurate, but it might guide people with the text that's in #3490 to help recreaate how I got here.

This PR encompasses a pair of fixes that are needed simultaneously to make the Windows Terminal work correctly.

  • Conpty was not emitting the correct thing when you'd decrease the height of the viewport. When you increase the height of the window, we'd both invalidate the entire buffer, and insert new lines to the bottom of the buffer. What this meant is that on every height-only resize, we'd re-emit the entire viewport.
    • If you resized down twice (From R to R-1 to R-2), once during the frame being emitted by conpty, the Terminal would try to process the R-1 lines emitted by conpty when there are only R-2 available rows in the terminal buffer. This would tlead to duplicated lines.
  • This buggy conpty behavior was causing us to correctly believe that the terminal viewport should remain "stuck" to the top position. That was what was causing us to apparently erase lines from the scrollback as we'd resize down. So this also changes the terminal to stick to the bottom when the viewport height changes.

This involved a bunch of changes throughout the codebase to make sure we weren't just calling TriggerRedraw on the entire viewport when we resize the buffer. Magically, conpty was pretty good about knowing what actually changed, though that did need some updating as well (in VtEngine::UpdateViewport).

As with any conpty change, I'm horrified that this will break in new and more horrifying ways. I'm hoping that a long bake time will help us identify bugs in this changelist (if there are any).

Validation Steps Performed

In VtPipeTerm and Windows Terminal:

  1. wsl seq 100
  2. resize down - scroll to make sure buffer has the right contents
  3. resize up - scroll to make sure buffer has the right contents
  4. resize down quickly - scroll to make sure buffer has the right contents
  5. resize up quickly - scroll to make sure buffer has the right contents
**Original Pull Request:** https://github.com/microsoft/terminal/pull/4354 **State:** closed **Merged:** No --- ## Summary of the Pull Request This PR fixes a bug in the Windows Terminal, where decreasing the height of the window would cause some lines from the scrollback to be lost. While a seemingly trivial bug, this actually involved some elaborate manipulation of how conpty decides to render a resize operation. ## References ## PR Checklist * [x] Closes #3490 * [x] I work here * [x] Tests added/passed - you don't even know * [n/a] Requires documentation to be updated ## Detailed Description of the Pull Request / Additional comments Conpty was not emitting the correct thing when you'd decrease the height of the viewport. When you increase the height of the window, we'd both invalidate the entire buffer, and insert new lines to the bottom of the buffer. What this meant is that on every height-only resize, we'd re-emit the entire viewport. - If you resized down twice (From `R` to `R-1` to `R-2`), once _during the frame being emitted by conpty_, the Terminal would try to process the `R-1` lines emitted by conpty when there are only `R-2` available rows in the terminal buffer. This would lead to duplicated lines. This involved a bunch of changes throughout the codebase to make sure we weren't just calling `TriggerRedraw` on the entire viewport when we resize the buffer. Magically, conpty was pretty good about knowing what actually changed, though that did need some updating as well (in `VtEngine::UpdateViewport`). - Importantly, there's a minor change to `ScreenInfo` to cause it to only invalidate wrapped lines during a ResizeWithReflow. Previously, we'd be invalidating the entire viewport, but that caused issues terminal-side. It's better to only tell the terminal what actually changed during the reflow. With those changes, the Terminal was changed to more intelligently stick to the right location in the buffer. When increasing the height of conpty, new lines always get inserted at the bottom of the viewport, so the terminal needs to stick to _roughly_ the old top's position to re-create this stateWhen resizing down, _empty_ lines are clipped from the conpty if there are any, then lines from the top are removed. This is obviously all very complicated, so I've added some tests to validate all this. `ConptyRoundtripTests::TestResizeHeight` is _elaborate_ and it does the right thing here, validating the contents of both conpty and the Terminal after emitting various numbers of lines into the buffer and doing arbitrary resizes. As with any conpty change, I'm horrified that this will break in new and more horrifying ways. I'm hoping that a long bake time will help us identify bugs in this changelist (if there are any). ## Validation Steps Performed In VtPipeTerm and Windows Terminal: 1. `wsl seq 100` 2. resize down - scroll to make sure buffer has the right contents 3. resize up - scroll to make sure buffer has the right contents 4. resize down _quickly_ - scroll to make sure buffer has the right contents 5. resize up _quickly_ - scroll to make sure buffer has the right contents Additionally, resize quickly from the corner, and ensure ll the lines are right. Aditionally, perform all the above with less than a full viewport of output. Aditidionally, after the above tests, perform a `sleep 2 ; printf "\e[6n"` and quickly hit <kbd>esc</kbd> to query the cursors position in conpty, and make sure it lines up with the Terminal's. Also play with resizing and PSReadline, and all the lovely things PSR does to the cursor. <details> <summary> This was the original PR body I had for this change. It's included here for future code archeologists. It's not really accurate, but it might guide people with the text that's in #3490 to help recreaate how I got here.</summary> This PR encompasses a pair of fixes that are needed simultaneously to make the Windows Terminal work correctly. * Conpty was not emitting the correct thing when you'd decrease the height of the viewport. When you increase the height of the window, we'd both invalidate the entire buffer, and insert new lines to the bottom of the buffer. What this meant is that on every height-only resize, we'd re-emit the entire viewport. - If you resized down twice (From `R` to `R-1` to `R-2`), once _during the frame being emitted by conpty_, the Terminal would try to process the `R-1` lines emitted by conpty when there are only `R-2` available rows in the terminal buffer. This would tlead to duplicated lines. * This buggy conpty behavior was causing us to correctly believe that the terminal viewport should remain "stuck" to the top position. That was what was causing us to apparently erase lines from the scrollback as we'd resize down. So this also changes the terminal to stick to the bottom when the viewport height changes. This involved a bunch of changes throughout the codebase to make sure we weren't just calling `TriggerRedraw` on the entire viewport when we resize the buffer. Magically, conpty was pretty good about knowing what actually changed, though that did need some updating as well (in `VtEngine::UpdateViewport`). As with any conpty change, I'm horrified that this will break in new and more horrifying ways. I'm hoping that a long bake time will help us identify bugs in this changelist (if there are any). ## Validation Steps Performed In VtPipeTerm and Windows Terminal: 1. `wsl seq 100` 2. resize down - scroll to make sure buffer has the right contents 3. resize up - scroll to make sure buffer has the right contents 4. resize down _quickly_ - scroll to make sure buffer has the right contents 5. resize up _quickly_ - scroll to make sure buffer has the right contents </details>
claunia added the pull-request label 2026-01-31 09:11:20 +00:00
Sign in to join this conversation.
No Label pull-request
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#25718