Skip to content

Prevent TerminalLogger corruption during terminal resize#14370

Open
AlesProkop with Copilot wants to merge 7 commits into
mainfrom
copilot/fix-terminal-logger-resizing-issue
Open

Prevent TerminalLogger corruption during terminal resize#14370
AlesProkop with Copilot wants to merge 7 commits into
mainfrom
copilot/fix-terminal-logger-resizing-issue

Conversation

Copilot AI commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Fixes: #14344

Summary

  • Poll terminal dimensions on every refresh so resizes immediately invalidate stale frame geometry.
  • Preserve the existing erase-and-redraw path when dimensions change.

Customer Impact

Shrinking a terminal during a build no longer leaves wrapped duration fragments and corrupted status output.

Regression?

No. Unchanged dimensions retain the existing delta-rendering behavior.

Testing

Added regression coverage for shrinking an active terminal from 120 to 40 columns.

Risk

Low. The change adds inexpensive terminal dimension reads to the existing 30 Hz refresh loop.

Copilot AI linked an issue Jul 15, 2026 that may be closed by this pull request
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Hello @copilot, I noticed that you’re changing an .swr file or any file under src/Package/MSBuild.VSSetup.. Please make sure to validate this change by an experimental VS insertion. This is accomplished by pushing to an exp/* branch, which requires write permissions to this repo.

Co-authored-by: AlesProkop <276576870+AlesProkop@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix terminal logger display issue when resizing Prevent TerminalLogger corruption during terminal resize Jul 15, 2026
Copilot AI requested a review from AlesProkop July 15, 2026 12:24
github-actions Bot added a commit that referenced this pull request Jul 15, 2026
Recurring reviewer feedback (PRs #14356, #14370, rainersigwald) flagged
direct terminal writes for immediate messages instead of using the
established RenderImmediateMessage path.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@AlesProkop
AlesProkop marked this pull request as ready for review July 17, 2026 12:25
Copilot AI review requested due to automatic review settings July 17, 2026 12:25

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Improves TerminalLogger’s live node display rendering stability by making refreshes always consult the current terminal dimensions so a terminal resize triggers the existing erase-and-redraw path immediately, preventing corrupted/wrapped output during active builds.

Changes:

  • Simplified the refresher thread loop to call a new Refresh() method each frame.
  • Introduced TerminalLogger.Refresh() to centralize refresh locking and ensure terminal size is checked per refresh.
  • Added a regression unit test that simulates shrinking the terminal width and asserts the logger emits the erase sequence.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
src/Build/Logging/TerminalLogger/TerminalLogger.cs Refactors refresher loop to refresh each frame via Refresh(), ensuring terminal resize is detected promptly.
src/Build.UnitTests/TerminalLogger_Tests.cs Adds a resizable terminal test double and a regression test for resize-triggered redraw behavior.

Comment thread src/Build/Logging/TerminalLogger/TerminalLogger.cs
Comment thread src/Build.UnitTests/TerminalLogger_Tests.cs Outdated
Comment thread src/Build.UnitTests/TerminalLogger_Tests.cs
{
if (_currentFrame.NodesCount > 0)
{
// Querying the terminal for it's dimensions is expensive, so we only do it every 30 frames e.g. once a second.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems to me that this change undoes this optimization (which is actually pretty important, check the historical ticket that introduced this).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right. Changed it so the optimization is preserved. Now, dimensions are queried once every 30 frames. However, after detecting a resize, querying increases to 30 hz until dimensions are stable for three frames. I think this is a good trade-off between optimization and not having the terminal "ugly".

@AlesProkop

Copy link
Copy Markdown
Member

TerminalLogger already remembers how many rows its live node block occupies and moves the cursor up by that amount before repainting. The problem is that this count becomes invalid after a resize: the terminal reflows previously written lines, so one old physical row may become two or more new rows.

So, we cannot effectively (without second buffer) determine how many of the rows can be rewritten without potentionally corrupting the terminal.

We have effectively two options:

  1. Polling every frame fixes the behavior (in a sense, but it is not still "beautiful enough" in my opinion). There is a cheaper way than what was done before the optimization to poll every frame. And that is replacing the calls of both Console.BufferWidth/BufferHeight with one call of GetConsoleScreenBufferInfo.

  2. Somewhat hybrid approach; poll once per second and if we detect a resize, we poll every frame until it is stable again. This preserves the optimization but produces corruption that is quite severe, because detecting the first resize requires polling the terminal, so the detection can be delayed by a second.

By my micro banchmark, these are the times that are needed for the approaches:

  • 30 double queries/sec: ~974 µs/sec
  • Existing 1 Hz throttle: ~32 µs/sec
  • 30 queries/sec: ~490 µs/sec

So, the outcome if this is:

  • 1 Hz polling: preserves maximum performance, but resizing remains visibly broken.
  • Per-frame double queries and per-frame one query somewhat fix the ugly terminal (of the live rows) but are more expensive.

So the question is: Do we want to keep performance in the cost of "ugly" resizing or do we want to improve the UX in cost of some time?
cc: @rainersigwald, @baronfel

@AlesProkop
AlesProkop requested a review from AR-May July 24, 2026 11:33
@baronfel

Copy link
Copy Markdown
Member

what impact does this have on a reasonably-sized build, like OrchardCore?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Resizing TerminalLogger down is ugly

5 participants