From 08409d167deba8950495d9737fb54b0cc6634f4c Mon Sep 17 00:00:00 2001 From: Ogulcan Celik Date: Sun, 19 Jul 2026 22:11:31 +0300 Subject: fix: show current workspace name in close confirmation refs #1364 --- src/ui/dialogs.rs | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 107 insertions(+), 5 deletions(-) (limited to 'src/ui') diff --git a/src/ui/dialogs.rs b/src/ui/dialogs.rs index ff40693b..9575cfe9 100644 --- a/src/ui/dialogs.rs +++ b/src/ui/dialogs.rs @@ -12,6 +12,7 @@ use super::widgets::{ render_modal_header, render_modal_shell, render_panel_shell, ActionButtonSpec, }; use crate::app::{state::WorktreeOpenState, AppState, Mode}; +use crate::terminal::TerminalRuntimeRegistry; const NEW_LINKED_WORKTREE_POPUP_WIDTH: u16 = 68; const NEW_LINKED_WORKTREE_POPUP_HEIGHT: u16 = 12; @@ -596,11 +597,14 @@ fn render_open_worktree_search( frame.render_widget(Paragraph::new(Line::from(spans)), area); } -fn confirm_close_overlay_text(app: &AppState) -> (String, String) { +fn confirm_close_overlay_text( + app: &AppState, + terminal_runtimes: &TerminalRuntimeRegistry, +) -> (String, String) { let ws_name = app .workspaces .get(app.selected) - .map(|ws| ws.display_name()) + .map(|ws| ws.display_name_from(&app.terminals, terminal_runtimes)) .unwrap_or_else(|| "?".to_string()); let selected_space = app .workspaces @@ -659,8 +663,13 @@ fn confirm_close_overlay_text(app: &AppState) -> (String, String) { (title.to_string(), detail) } -pub(super) fn render_confirm_close_overlay(app: &AppState, frame: &mut Frame, area: Rect) { - let (title, detail) = confirm_close_overlay_text(app); +pub(super) fn render_confirm_close_overlay( + app: &AppState, + terminal_runtimes: &TerminalRuntimeRegistry, + frame: &mut Frame, + area: Rect, +) { + let (title, detail) = confirm_close_overlay_text(app, terminal_runtimes); super::dim_background(frame, area); @@ -765,6 +774,98 @@ mod tests { use super::{confirm_close_overlay_text, render_new_linked_worktree_overlay}; + #[test] + fn confirm_close_text_uses_live_workspace_cwd_label() { + let mut app = AppState::test_new(); + let mut workspace = Workspace::test_new("initial"); + workspace.custom_name = None; + workspace.identity_cwd = "/projects/original".into(); + let root_pane = workspace.tabs[0].root_pane; + let terminal_id = workspace.tabs[0].panes[&root_pane] + .attached_terminal_id + .clone(); + app.workspaces = vec![workspace]; + app.ensure_test_terminals(); + app.terminals.get_mut(&terminal_id).unwrap().cwd = "/projects/current".into(); + app.selected = 0; + + let terminal_runtimes = crate::terminal::TerminalRuntimeRegistry::new(); + let (title, detail) = confirm_close_overlay_text(&app, &terminal_runtimes); + + assert_eq!(title, "Close workspace?"); + assert_eq!(detail, "current — 1 pane"); + } + + #[cfg(unix)] + #[tokio::test] + async fn confirm_close_text_prefers_live_runtime_cwd_over_stale_terminal_cwd() { + let root = std::env::temp_dir().join(format!( + "herdr-confirm-close-runtime-cwd-{}", + std::process::id() + )); + let stale_cwd = root.join("original"); + let live_cwd = root.join("current"); + std::fs::create_dir_all(&live_cwd).unwrap(); + + let mut app = AppState::test_new(); + let mut workspace = Workspace::test_new("initial"); + workspace.custom_name = None; + workspace.identity_cwd = stale_cwd.clone(); + let root_pane = workspace.tabs[0].root_pane; + let terminal_id = workspace.tabs[0].panes[&root_pane] + .attached_terminal_id + .clone(); + app.workspaces = vec![workspace]; + app.ensure_test_terminals(); + app.selected = 0; + + let (events, _) = tokio::sync::mpsc::channel(4); + let runtime = crate::terminal::TerminalRuntime::spawn( + root_pane, + 24, + 80, + live_cwd, + 0, + crate::terminal_theme::TerminalTheme::default(), + crate::pane::PaneShellConfig::new("/bin/sh", crate::config::ShellModeConfig::NonLogin), + &crate::pane::PaneLaunchEnv::default(), + events, + std::sync::Arc::new(tokio::sync::Notify::new()), + std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false)), + ) + .unwrap(); + let mut terminal_runtimes = crate::terminal::TerminalRuntimeRegistry::new(); + terminal_runtimes.insert(terminal_id, runtime); + + let (_, detail) = confirm_close_overlay_text(&app, &terminal_runtimes); + + assert_eq!(detail, "current — 1 pane"); + + drop(terminal_runtimes); + std::fs::remove_dir_all(root).unwrap(); + } + + #[test] + fn confirm_close_text_uses_selected_custom_name_instead_of_active_workspace_cwd() { + let mut app = AppState::test_new(); + let active = Workspace::test_new("active"); + let selected = Workspace::test_new("selected"); + let selected_root = selected.tabs[0].root_pane; + let selected_terminal_id = selected.tabs[0].panes[&selected_root] + .attached_terminal_id + .clone(); + app.workspaces = vec![active, selected]; + app.ensure_test_terminals(); + app.terminals.get_mut(&selected_terminal_id).unwrap().cwd = "/projects/current".into(); + app.active = Some(0); + app.selected = 1; + + let terminal_runtimes = crate::terminal::TerminalRuntimeRegistry::new(); + let (_, detail) = confirm_close_overlay_text(&app, &terminal_runtimes); + + assert_eq!(detail, "selected — 1 pane"); + } + #[test] fn confirm_close_text_reports_parent_group_scope() { let mut app = AppState::test_new(); @@ -787,7 +888,8 @@ mod tests { app.workspaces = vec![parent, child]; app.selected = 0; - let (title, detail) = confirm_close_overlay_text(&app); + let terminal_runtimes = crate::terminal::TerminalRuntimeRegistry::new(); + let (title, detail) = confirm_close_overlay_text(&app, &terminal_runtimes); assert_eq!(title, "Close worktree group?"); assert_eq!(detail, "main — 2 workspaces, 2 panes"); -- cgit v1.2.3