diff options
| author | Eric Yue <jiacheng.yue@foxmail.com> | 2026-09-21 01:33:11 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-09-20 19:33:11 +0200 |
| commit | f090ce95d05d2e7811869be93f9a23bf4ac2c3af (patch) | |
| tree | d5a1a447fd6043056e5ea3cb1a9bd0419957e57b /src/client/shell/overlay_input.rs | |
| parent | f10df75c8a5f1b5e5f90689c3a8ceb6758366e05 (diff) | |
fix: confirm closing the last tab in the tui (#4409)
* fix: confirm closing the last tab in the tui
refs #4379
* docs: clarify last-tab worktree confirmation in translations
refs #4379
---------
Co-authored-by: JJ Liebig <jonathan.liebig@gmail.com>
Diffstat (limited to 'src/client/shell/overlay_input.rs')
| -rw-r--r-- | src/client/shell/overlay_input.rs | 91 |
1 files changed, 76 insertions, 15 deletions
diff --git a/src/client/shell/overlay_input.rs b/src/client/shell/overlay_input.rs index e4248304..10bd4a45 100644 --- a/src/client/shell/overlay_input.rs +++ b/src/client/shell/overlay_input.rs @@ -877,19 +877,7 @@ impl ClientShellState { if matches!(self.overlay, Some(ClientShellOverlay::ConfirmClose(_))) { if key.code == KeyCode::Enter { - let Some(ClientShellOverlay::ConfirmClose(confirm)) = self.overlay.take() else { - return; - }; - self.push_endpoint_method( - crate::api::schema::Method::WorkspaceClose( - crate::api::schema::WorkspaceCloseParams { - workspace_id: confirm.workspace_id, - close_group: true, - }, - ), - outcome, - ); - outcome.repaint = true; + self.accept_close_confirmation(outcome); } else if key.code == KeyCode::Esc { self.overlay = None; self.mode = ClientShellMode::Navigate; @@ -999,16 +987,74 @@ impl ClientShellState { outcome.repaint = true; } + pub(super) fn request_tab_close(&mut self, tab_id: String, outcome: &mut ClientShellInput) { + let workspace_id = self.snapshot.as_deref().and_then(|snapshot| { + let target = snapshot.tabs.iter().find(|tab| tab.tab_id == tab_id)?; + (self.config.confirm_close + && !snapshot + .tabs + .iter() + .any(|tab| tab.workspace_id == target.workspace_id && tab.tab_id != tab_id)) + .then(|| target.workspace_id.clone()) + }); + if let Some(workspace_id) = workspace_id { + if self.open_close_confirmation(workspace_id, Some(tab_id.clone())) { + outcome.repaint = true; + return; + } + } + self.push_endpoint_method( + crate::api::schema::Method::TabClose(crate::api::schema::TabTarget { tab_id }), + outcome, + ); + } + + pub(super) fn accept_close_confirmation(&mut self, outcome: &mut ClientShellInput) { + let Some(ClientShellOverlay::ConfirmClose(confirm)) = self.overlay.take() else { + return; + }; + outcome.repaint = true; + let method = if let Some(target) = confirm.tab_target { + if target.workspace.endpoint_id != self.active_endpoint_id + || !self.navigation_target_valid(&target.workspace) + || !self.snapshot.as_deref().is_some_and(|snapshot| { + snapshot.tabs.iter().any(|tab| { + tab.tab_id == target.tab_id + && tab.workspace_id == target.workspace.workspace_id + }) + }) + { + self.receive_endpoint_unavailable( + "Close target changed; try closing the tab again".into(), + ); + return; + } + crate::api::schema::Method::TabClose(crate::api::schema::TabTarget { + tab_id: target.tab_id, + }) + } else { + crate::api::schema::Method::WorkspaceClose(crate::api::schema::WorkspaceCloseParams { + workspace_id: confirm.workspace_id, + close_group: true, + }) + }; + self.push_endpoint_method(method, outcome); + } + pub(super) fn open_confirm_close_overlay(&mut self, workspace_id: String) { + self.open_close_confirmation(workspace_id, None); + } + + fn open_close_confirmation(&mut self, workspace_id: String, tab_id: Option<String>) -> bool { let Some(snapshot) = self.snapshot.as_deref() else { - return; + return false; }; let Some(workspace) = snapshot .workspaces .iter() .find(|workspace| workspace.workspace_id == workspace_id) else { - return; + return false; }; let group_key = workspace .worktree @@ -1030,6 +1076,19 @@ impl ClientShellState { }) .unwrap_or_else(|| vec![workspace]); let closes_group = group.len() > 1; + // Keep parent-group tab closes on the existing server confirmation path. + if tab_id.is_some() && closes_group { + return false; + } + let tab_target = if let Some(tab_id) = tab_id { + let Some(workspace) = self.navigation_target(&self.active_endpoint_id, &workspace_id) + else { + return false; + }; + Some(ClientTabCloseConfirmation { tab_id, workspace }) + } else { + None + }; let pane_count = group .iter() .map(|member| { @@ -1053,6 +1112,7 @@ impl ClientShellState { self.overlay = Some(ClientShellOverlay::ConfirmClose( ClientConfirmCloseOverlay { workspace_id, + tab_target, title: if closes_group { "Close worktree group?".to_owned() } else { @@ -1061,5 +1121,6 @@ impl ClientShellState { detail: format!("{} — {scope}", workspace.label), }, )); + true } } |
