Repository navigation
fix(terminal): prevent redundant focus events causing Powerlevel10k redraws - #1579
Conversation
…edraws Add lastFocusState tracking to TerminalSurface to avoid sending duplicate focus events to the terminal surface. This fixes double prompt / extra redraw issues when using zsh with Powerlevel10k and switching workspaces. Fixes manaflow-ai#1566
|
@BillionClaw is attempting to deploy a commit to the Manaflow Team on Vercel. A member of the Team first needs to authorize it. |
There was a problem hiding this comment.
Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.
📝 WalkthroughWalkthroughA state tracking mechanism was added to prevent redundant focus events in TerminalSurface. The Changes
Estimated code review effort🎯 1 (Trivial) | ⏱️ ~3 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
📝 Coding Plan
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@Sources/GhosttyTerminalView.swift`:
- Around line 3297-3301: The focus-deduplication boolean lastFocusState can get
out of sync because other code paths call ghostty_surface_set_focus(...)
directly; update TerminalSurface.setFocus(_:) to be the single canonical setter
for focus changes and ensure all first-responder / direct focus transitions
route through it (or update lastFocusState there) so the cache and libghostty
state stay consistent: find usages of ghostty_surface_set_focus(...) outside
TerminalSurface.setFocus(_:) and either replace those calls to invoke
TerminalSurface.setFocus(_:) or add logic to update lastFocusState whenever
ghostty_surface_set_focus(...) is called, keeping lastFocusState,
TerminalSurface.setFocus(_:), and ghostty_surface_set_focus(...) behavior
coherent.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 6a7ff4e6-e1b9-450b-a843-7c7350d99201
📒 Files selected for processing (1)
Sources/GhosttyTerminalView.swift
| // Only send focus events when the state changes to avoid redundant | ||
| // prompt redraws with zsh themes like Powerlevel10k. | ||
| guard focused != lastFocusState else { return } | ||
| lastFocusState = focused | ||
| ghostty_surface_set_focus(surface, focused) |
There was a problem hiding this comment.
Focus dedupe state can desync from actual runtime focus.
Line 3299 relies on lastFocusState, but runtime focus is also changed through direct ghostty_surface_set_focus(...) paths outside TerminalSurface.setFocus(_:). That can leave this cache stale and still allow duplicate focus events (or skip needed ones).
Suggested fix
- private var lastFocusState: Bool = false
+ private var lastFocusState: Bool?
func setFocus(_ focused: Bool) {
guard let surface = surface else { return }
- guard focused != lastFocusState else { return }
+ if let lastFocusState, focused == lastFocusState { return }
lastFocusState = focused
ghostty_surface_set_focus(surface, focused)Also route first-responder focus transitions through TerminalSurface.setFocus(_:) (or update lastFocusState in those direct call sites) so the dedupe cache and libghostty focus never diverge.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@Sources/GhosttyTerminalView.swift` around lines 3297 - 3301, The
focus-deduplication boolean lastFocusState can get out of sync because other
code paths call ghostty_surface_set_focus(...) directly; update
TerminalSurface.setFocus(_:) to be the single canonical setter for focus changes
and ensure all first-responder / direct focus transitions route through it (or
update lastFocusState there) so the cache and libghostty state stay consistent:
find usages of ghostty_surface_set_focus(...) outside
TerminalSurface.setFocus(_:) and either replace those calls to invoke
TerminalSurface.setFocus(_:) or add logic to update lastFocusState whenever
ghostty_surface_set_focus(...) is called, keeping lastFocusState,
TerminalSurface.setFocus(_:), and ghostty_surface_set_focus(...) behavior
coherent.
There was a problem hiding this comment.
1 issue found across 1 file
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="Sources/GhosttyTerminalView.swift">
<violation number="1" location="Sources/GhosttyTerminalView.swift:3299">
P2: lastFocusState persists across surface teardown/recreation, so a newly created ghostty_surface_t can miss its initial focus update when focused state is unchanged, desynchronizing focus state.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| guard let surface = surface else { return } | ||
| // Only send focus events when the state changes to avoid redundant | ||
| // prompt redraws with zsh themes like Powerlevel10k. | ||
| guard focused != lastFocusState else { return } |
There was a problem hiding this comment.
P2: lastFocusState persists across surface teardown/recreation, so a newly created ghostty_surface_t can miss its initial focus update when focused state is unchanged, desynchronizing focus state.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At Sources/GhosttyTerminalView.swift, line 3299:
<comment>lastFocusState persists across surface teardown/recreation, so a newly created ghostty_surface_t can miss its initial focus update when focused state is unchanged, desynchronizing focus state.</comment>
<file context>
@@ -3291,6 +3294,10 @@ final class TerminalSurface: Identifiable, ObservableObject {
guard let surface = surface else { return }
+ // Only send focus events when the state changes to avoid redundant
+ // prompt redraws with zsh themes like Powerlevel10k.
+ guard focused != lastFocusState else { return }
+ lastFocusState = focused
ghostty_surface_set_focus(surface, focused)
</file context>
…edraws (manaflow-ai#1579) Add lastFocusState tracking to TerminalSurface to avoid sending duplicate focus events to the terminal surface. This fixes double prompt / extra redraw issues when using zsh with Powerlevel10k and switching workspaces. Fixes manaflow-ai#1566 Co-authored-by: BillionClaw <267901332+BillionClaw@users.noreply.github.com>
Fixes #1566
Problem
When using zsh with Powerlevel10k in cmux, there was a double prompt / extra redraw issue when switching workspaces or using right-aligned elements on the prompt.
Root Cause
The
setFocusmethod in TerminalSurface unconditionally calledghostty_surface_set_focuseven when the focus state hadn't changed. This caused focus events (CSI I/O sequences) to be sent to the terminal on every workspace switch, triggering Powerlevel10k to redraw its prompt unnecessarily.Solution
Add
lastFocusStatetracking to TerminalSurface to avoid sending duplicate focus events to the terminal surface.Changes
private var lastFocusState: Bool = falseto track focus statesetFocus(_ focused: Bool)to only send focus events when the state actually changesTesting
swift buildSummary by cubic
Prevent redundant focus events in TerminalSurface that triggered zsh/Powerlevel10k prompt redraws and double prompts on workspace switches. Track the last focus state and only call
ghostty_surface_set_focuswhen it changes (fixes #1566).Written for commit 7ee57c3. Summary will update on new commits.
Summary by CodeRabbit