From 74505861e40c48e070e711bd4de662a17b0939b3 Mon Sep 17 00:00:00 2001 From: Eric Yue Date: Sun, 20 Sep 2026 22:33:50 +0800 Subject: fix: keep workspace navigation visible in terminal theme (#4408) * fix: keep workspace navigation visible in terminal theme refs #4300 * fix: clear workspace highlight on directional pane focus refs #4300 --------- Co-authored-by: JJ Liebig --- src/client/shell/workspace_navigation.rs | 54 ++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) (limited to 'src/client/shell/workspace_navigation.rs') diff --git a/src/client/shell/workspace_navigation.rs b/src/client/shell/workspace_navigation.rs index 6139fe0d..19fa1a39 100644 --- a/src/client/shell/workspace_navigation.rs +++ b/src/client/shell/workspace_navigation.rs @@ -9,6 +9,13 @@ pub(super) struct WorkspaceNavigationTarget { generation: Option, } +/// Display-only continuity while a direct focus request awaits its authoritative snapshot. +pub(super) struct PendingWorkspaceHighlight { + pub(super) target: WorkspaceNavigationTarget, + pub(super) request_id: String, + expires_at: std::time::Instant, +} + impl WorkspaceNavigationTarget { pub(super) fn matches(&self, endpoint_id: &ClientEndpointId, workspace_id: &str) -> bool { &self.endpoint_id == endpoint_id && self.workspace_id == workspace_id @@ -16,6 +23,35 @@ impl WorkspaceNavigationTarget { } impl ClientShellState { + pub(crate) fn tick_workspace_highlight(&mut self, now: std::time::Instant) -> bool { + if self + .pending_workspace_highlight + .as_ref() + .is_some_and(|pending| now >= pending.expires_at) + { + self.pending_workspace_highlight = None; + return true; + } + false + } + + pub(super) fn reconcile_pending_workspace_highlight(&mut self) { + if self + .pending_workspace_highlight + .as_ref() + .is_some_and(|pending| { + pending.target.endpoint_id != self.active_endpoint_id + || !self.navigation_target_valid(&pending.target) + || self.snapshot.as_deref().is_some_and(|snapshot| { + snapshot.focused_workspace_id.as_deref() + == Some(pending.target.workspace_id.as_str()) + }) + }) + { + self.pending_workspace_highlight = None; + } + } + pub(super) fn navigation_target( &self, endpoint_id: &ClientEndpointId, @@ -140,11 +176,25 @@ impl ClientShellState { outcome.repaint = true; return; } + let action_index = outcome.actions.len(); if self.focus_or_activate( - target.endpoint_id, - ClientEndpointFocusTarget::Workspace(target.workspace_id), + target.endpoint_id.clone(), + ClientEndpointFocusTarget::Workspace(target.workspace_id.clone()), outcome, ) { + // Endpoint handoffs already retain their coherent source frame in the runtime. + // Only retain a highlight if a focus request was actually enqueued. + if let Some(ClientShellAction::Endpoint { request, .. }) = + outcome.actions.get(action_index) + { + self.pending_workspace_highlight = Some(PendingWorkspaceHighlight { + target, + request_id: request.id.clone(), + // A later focus can be coalesced with this one before a snapshot is sent. + expires_at: std::time::Instant::now() + std::time::Duration::from_secs(1), + }); + self.reconcile_pending_workspace_highlight(); + } self.mode = ClientShellMode::Terminal; self.navigate_workspace_id = None; } -- cgit v1.2.3