-
Notifications
You must be signed in to change notification settings - Fork 3
Description
Problem Description
When launching TUI applications (Claude Code, vim, htop) after running shell commands, old shell output remains visible at the bottom of the TUI screen, creating "ghost content".
Steps to Reproduce
# Fill screen with output
for i in {1..50}; do echo "Line $i"; done
# Launch TUI app
claude codeExpected: Clean TUI display
Actual: "Line 1", "Line 2", etc. visible at bottom of TUI interface
Investigation Summary
Initial Hypothesis (INCORRECT)
- Thought it was related to alternate buffer switching
- Reality: Claude Code doesn't use alternate buffer mode
Current Leading Theory: Double Redraw Race Condition
When TUI apps clear the screen (CSI 2J), the following sequence occurs:
T+0ms: eraseInDisplay(mode=2) called
T+5ms: terminalTextBuffer.batch { clearLines() }
└─ Batch ends → fires ModelListener.modelChanged()
└─ Calls display.requestRedraw() → REDRAW #1 (queued with debounce)
T+10ms: myDisplay.forceRedraw() → REDRAW #2 (direct to Main dispatcher)
T+20ms: RACE CONDITION - Two redraws executing with different buffer snapshots
└─ INTERMEDIATE STATE RENDERS ← Potential cause of ghost content
Key files involved:
BossTerminal.kt:792-820(mode 2 clear)BossTerminal.kt:822-846(mode 3 clear)TerminalTextBuffer.kt:305-315(endBatch fires ModelListener)TabController.kt:289-294(ModelListener calls requestRedraw)
Debug Logging Added
Temporary debug logging can be added to /tmp/bossterm-debug.log to trace:
- When eraseInDisplay modes 0/1/2/3 execute
- When forceRedraw() is called
- When actualRedraw() increments _redrawTrigger
- Redraw sequence timing
Attempted Fix (Reverted)
Added criticalBatch() method to suppress automatic ModelListener callbacks during mode 2/3 clears, leaving only the explicit forceRedraw(). This eliminated the double redraw but broke input handling - needs further investigation into why.
Additional Observations
- Issue occurs specifically when TUI apps launch after shell output
- Does not occur when launching TUI in clean terminal
- May be related to synchronized update mode (OSC 2026) timing
- Suppression mechanisms exist for partial erases (mode 0/1) but not full clears
Next Steps
- Investigate why suppressing automatic redraws broke input handling
- Consider if the race condition is actually the root cause or just a symptom
- Analyze TUI initialization sequence more carefully (setSynchronizedUpdate timing)
- Test with other TUI apps to see if behavior is consistent
- Consider if the issue is in the snapshot rendering mechanism instead
Related Code
- Rendering:
ComposeTerminalDisplay.kt(requestRedraw, forceRedraw, actualRedraw) - Buffer:
TerminalTextBuffer.kt(batch operations, ModelListener) - Terminal:
BossTerminal.kt(eraseInDisplay modes) - Snapshot:
IncrementalSnapshotBuilder.kt(lock-free rendering)
Environment
- Platform: Linux
- Terminal: BossTerm
- Test apps: Claude Code, vim, htop, any TUI that clears screen
Note: This is a complex rendering issue that requires careful investigation to avoid breaking existing functionality. The double redraw theory seems plausible but needs more validation.