fix(renderer): prevent terminal output disappearing on window resize#2898
Open
hessnd wants to merge 4 commits intotailcallhq:mainfrom
Open
fix(renderer): prevent terminal output disappearing on window resize#2898hessnd wants to merge 4 commits intotailcallhq:mainfrom
hessnd wants to merge 4 commits intotailcallhq:mainfrom
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fix terminal output disappearing when the window is resized during active streaming, affecting both the interactive TUI and ZSH plugin inline mode.
Closes #2893
Context
When using Forge in Ghostty (and potentially other terminals), resizing the window during streaming causes rendered output to vanish. The root cause is twofold: (1) the markdown streaming renderer captures terminal width once at construction and never updates it on resize, and (2) the spinner's cursor manipulation writes stale cursor positions after the terminal reflows content.
Changes
Renderer::set_width()andStreamdownRenderer::set_width()inforge_markdown_streamto update the rendering width in place without tearing down parser/renderer statelast_widthfield toStreamingWriterinforge_main, initialized fromterm_width()at constructionStreamingWriter::ensure_renderer()to pollterm_width()on every call, comparing againstlast_widthand callingset_width()when the terminal has been resizedspinner.stop(None)) before width updates to preventfinish_and_clear()from erasing content with stale cursor positionsKey Implementation Details
The fix uses in-place width polling rather than SIGWINCH signal handling or renderer tear-down/recreate.
ioctl(TIOCGWINSZ)costs ~100ns-1us reading a kernel-cached struct, making per-call polling negligible. In-place update was chosen over tear-down becauseStreamdownRenderer::finish()callsparser.finalize(), which emits closing events for all open block structures — a mid-stream recreate would lose code block syntax highlighting, blockquote borders, list numbering, and table state. The polling approach also avoids SIGWINCH delivery issues in the ZSH plugin's ZLE widget context, where ZSH's own signal handler may consume the signal before Forge sees it.Testing
cargo check --workspace cargo test -p forge_main -p forge_markdown_streamManually verified in Ghostty:
: prompt) — works correctly