Fix terminal state loss when switching workspaces
Summary
Fixes terminal state loss and display corruption when switching between workspaces in WaveTerminal.
Problem
When switching workspaces, TUI applications (vim, htop, opencode, etc.) would:
- Lose ability to scroll
- Display corrupted/overlapping text (gibberish screen)
- Lose alternate screen buffer state
Root Cause
The switchworkspace operation called removeAllChildViews() which destroyed all tab views. When recreated, xterm.js terminal instances lost their state even though backend shell processes continued running.
Tab switching vs Workspace switching:
- Tab switching: Repositions views (preserves state) ✅
- Workspace switching: Destroyed and recreated views (lost state) ❌
Solution
Cache tab views across workspace switches instead of destroying them:
- On workspace switch: Remove cached views from DOM (prevents rendering conflicts)
- On switch back: Re-add cached view to DOM if available
- Cleanup: Destroy cached views only when tab explicitly closed or window closes
Implementation Details
Key Changes
// emain/emain-window.ts
+ allTabViewsCache: Map<string, WaveTabView> // Cache field
// Workspace switch: cache instead of destroy
- this.removeAllChildViews()
+ for (const [tabId, tabView] of this.allLoadedTabViews.entries()) {
+ this.contentView.removeChildView(tabView) // Remove from DOM
+ this.allTabViewsCache.set(tabId, tabView) // Keep alive in cache
+ }
// Tab load: check cache first
+ let tabView = this.allTabViewsCache.get(tabId)
+ if (tabView) {
+ this.contentView.addChildView(tabView) // Re-add to DOM
+ this.allTabViewsCache.delete(tabId)
+ } else {
+ [tabView, tabInitialized] = await getOrCreateWebViewForTab(...)
+ }
// IPC lookup: search both loaded and cached
- if (ww.allLoadedTabViews.has(tabId))
+ if (ww.allLoadedTabViews.has(tabId) || ww.allTabViewsCache.has(tabId))
Bug Fixes (commits 2-4)
- Commit 2: Add defensive check for cached views in contentView (during development)
- Commit 3: Fix gibberish screen - properly remove cached views from DOM instead of positioning off-screen
-
Commit 4: Fix IPC event handling for cached tabs by updating
getWaveWindowByTabId
What This Preserves
- Terminal buffer state (normal and alternate screen modes)
- Scrollback history and scrolling capability
- Running processes and their output
- Cursor position and all terminal modes
- Clean rendering (no overlapping terminals)
Memory Management
- Cached views kept alive indefinitely (like traditional terminal apps)
- Destroyed only when: tab explicitly closed OR window closed
- Typical memory: 1-5MB per cached terminal
- No timeout - can switch back after hours
Testing
Tested with opencode (TUI app):
- ✅ Run opencode in workspace A
- ✅ Switch to workspace B
- ✅ Switch back to workspace A (even after hours)
- ✅ Terminal state preserved, scrolling works correctly
- ✅ No display corruption or gibberish screen
- ✅ IPC events from cached tabs work correctly
Behavior Match
Now matches macOS Terminal, iTerm2, and other terminal emulators where terminal state is preserved across workspace/tab switches.
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
Walkthrough
Adds a per-window tab-view cache (allTabViewsCache: Map<string, WaveTabView>) to WaveBrowserWindow, initialized in the constructor. On workspace switches, currently loaded tab views are moved into the cache instead of being destroyed; workspace restoration first checks the cache to reuse cached views and falls back to creating new web views. On window teardown, all cached tab views are destroyed and cleared. removeTabView and getWaveWindowByTabId are updated to consult and remove from the cache as well as loaded views. Cached views are destroyed only on explicit tab close or window teardown.
Estimated code review effort
🎯 3 (Moderate) | ⏱️ ~20 minutes
Pre-merge checks and finishing touches
❌ Failed checks (1 warning)
| Check name | Status | Explanation | Resolution |
|---|---|---|---|
| Docstring Coverage | ⚠️ Warning | Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. | You can run @coderabbitai generate docstrings to improve docstring coverage. |
✅ Passed checks (2 passed)
| Check name | Status | Explanation |
|---|---|---|
| Title check | ✅ Passed | The title 'Fix terminal state loss when switching workspaces' directly and clearly summarizes the main change in the PR, matching the primary problem being addressed. |
| Description check | ✅ Passed | The description is comprehensive and directly related to the changeset, providing detailed context on the problem, root cause, solution, implementation, and testing. |
✨ Finishing touches
- [ ] 📝 Generate docstrings
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 @coderabbitai help to get the list of available commands and usage tips.
Closing temporarily for additional debugging and testing. Will reopen after issues are resolved.
Fixed the gibberish screen issue! The problem was keeping cached views as children of contentView (positioned off-screen), causing multiple terminals to render on top of each other.
Changes in latest commit:
- Remove cached views from contentView during workspace switch
- Re-add them when reusing from cache
- Simplified removal logic
The display corruption should now be gone. Ready for review!