@@ -139,6 +139,7 @@ export class WaveBrowserWindow extends BaseWindow {
139139 waveWindowId : string ;
140140 workspaceId : string ;
141141 allLoadedTabViews : Map < string , WaveTabView > ;
142+ allTabViewsCache : Map < string , WaveTabView > ; // Cache for preserving tab views across workspace switches
142143 activeTabView : WaveTabView ;
143144 private canClose : boolean ;
144145 private deleteAllowed : boolean ;
@@ -218,6 +219,7 @@ export class WaveBrowserWindow extends BaseWindow {
218219 this . waveWindowId = waveWindow . oid ;
219220 this . workspaceId = waveWindow . workspaceid ;
220221 this . allLoadedTabViews = new Map < string , WaveTabView > ( ) ;
222+ this . allTabViewsCache = new Map < string , WaveTabView > ( ) ;
221223 const winBoundsPoller = setInterval ( ( ) => {
222224 if ( this . isDestroyed ( ) ) {
223225 clearInterval ( winBoundsPoller ) ;
@@ -352,6 +354,11 @@ export class WaveBrowserWindow extends BaseWindow {
352354 }
353355 tabView ?. destroy ( ) ;
354356 }
357+ // Also destroy any cached views
358+ for ( const tabView of this . allTabViewsCache . values ( ) ) {
359+ tabView ?. destroy ( ) ;
360+ }
361+ this . allTabViewsCache . clear ( ) ;
355362 }
356363
357364 async switchWorkspace ( workspaceId : string ) {
@@ -576,8 +583,27 @@ export class WaveBrowserWindow extends BaseWindow {
576583 return ;
577584 }
578585 console . log ( "processActionQueue switchworkspace newWs" , newWs ) ;
579- this . removeAllChildViews ( ) ;
580- console . log ( "destroyed all tabs" , this . waveWindowId ) ;
586+ // Move current tab views to cache instead of destroying them
587+ // This preserves terminal state (including alternate screen mode) across workspace switches
588+ for ( const [ tabId , tabView ] of this . allLoadedTabViews . entries ( ) ) {
589+ // Position off-screen but don't destroy
590+ if ( ! this . isDestroyed ( ) ) {
591+ const bounds = this . getContentBounds ( ) ;
592+ tabView . positionTabOffScreen ( bounds ) ;
593+ }
594+ // If tabId already in cache (edge case with rapid workspace switching), destroy the old cached view first
595+ const existingCachedView = this . allTabViewsCache . get ( tabId ) ;
596+ if ( existingCachedView ) {
597+ existingCachedView . destroy ( ) ;
598+ }
599+ this . allTabViewsCache . set ( tabId , tabView ) ;
600+ }
601+ console . log ( "cached" , this . allLoadedTabViews . size , "tabs for workspace" , this . workspaceId , this . waveWindowId ) ;
602+ // Note: Cached views are kept alive indefinitely and only destroyed when:
603+ // 1. The tab is explicitly closed by the user
604+ // 2. The window is closed (via removeAllChildViews)
605+ // This matches how traditional terminal apps work and prevents terminal state loss
606+
581607 this . workspaceId = entry . workspaceId ;
582608 this . allLoadedTabViews = new Map ( ) ;
583609 tabId = newWs . activetabid ;
@@ -586,7 +612,15 @@ export class WaveBrowserWindow extends BaseWindow {
586612 if ( tabId == null ) {
587613 return ;
588614 }
589- const [ tabView , tabInitialized ] = await getOrCreateWebViewForTab ( this . waveWindowId , tabId ) ;
615+ // Check cache first to reuse existing tab views across workspace switches
616+ let tabView = this . allTabViewsCache . get ( tabId ) ;
617+ let tabInitialized = true ;
618+ if ( tabView ) {
619+ console . log ( "reusing cached tab view" , tabId , this . waveWindowId ) ;
620+ this . allTabViewsCache . delete ( tabId ) ;
621+ } else {
622+ [ tabView , tabInitialized ] = await getOrCreateWebViewForTab ( this . waveWindowId , tabId ) ;
623+ }
590624 const primaryStartupTabFlag = entry . op === "switchtab" ? ( entry . primaryStartupTab ?? false ) : false ;
591625 await this . setTabViewIntoWindow ( tabView , tabInitialized , primaryStartupTabFlag ) ;
592626 } catch ( e ) {
@@ -618,14 +652,23 @@ export class WaveBrowserWindow extends BaseWindow {
618652 console . log ( "cannot remove active tab" , tabId , this . waveWindowId ) ;
619653 return ;
620654 }
621- const tabView = this . allLoadedTabViews . get ( tabId ) ;
655+ let tabView = this . allLoadedTabViews . get ( tabId ) ;
622656 if ( tabView == null ) {
623- console . log ( "removeTabView -- tabView not found" , tabId , this . waveWindowId ) ;
624- // the tab was never loaded, so just return
625- return ;
657+ // Check cache - tab might be from a different workspace
658+ tabView = this . allTabViewsCache . get ( tabId ) ;
659+ if ( tabView == null ) {
660+ console . log ( "removeTabView -- tabView not found in loaded or cache" , tabId , this . waveWindowId ) ;
661+ return ;
662+ }
663+ console . log ( "removeTabView -- removing from cache" , tabId , this . waveWindowId ) ;
664+ this . allTabViewsCache . delete ( tabId ) ;
665+ } else {
666+ this . allLoadedTabViews . delete ( tabId ) ;
667+ }
668+ // Remove from contentView (cached views are still children, just positioned off-screen)
669+ if ( ! this . isDestroyed ( ) ) {
670+ this . contentView . removeChildView ( tabView ) ;
626671 }
627- this . contentView . removeChildView ( tabView ) ;
628- this . allLoadedTabViews . delete ( tabId ) ;
629672 tabView . destroy ( ) ;
630673 }
631674
0 commit comments