aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-07-19 22:11:31 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-07-19 22:11:31 +0300
commit08409d167deba8950495d9737fb54b0cc6634f4c (patch)
tree25b73f6bbd759b45f22434b5e0ca0d90ff87a33e /src
parenta26a654351ee03b1a51d7b398f3bdff2c1ca920d (diff)
fix: show current workspace name in close confirmation
refs #1364
Diffstat (limited to 'src')
-rw-r--r--src/ui.rs4
-rw-r--r--src/ui/dialogs.rs112
2 files changed, 110 insertions, 6 deletions
diff --git a/src/ui.rs b/src/ui.rs
index b7dc3fb1..6fcb28c3 100644
--- a/src/ui.rs
+++ b/src/ui.rs
@@ -435,7 +435,9 @@ pub fn render_with_runtime_registry(
Mode::Prefix => render_prefix_overlay(app, frame, terminal_area),
Mode::Copy => render_copy_mode_overlay(app, frame, terminal_area),
Mode::Resize => render_resize_overlay(app, frame, terminal_area),
- Mode::ConfirmClose => render_confirm_close_overlay(app, frame, terminal_area),
+ Mode::ConfirmClose => {
+ render_confirm_close_overlay(app, terminal_runtimes, frame, terminal_area)
+ }
Mode::ContextMenu => {
render_context_menu(app, frame);
}
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);
@@ -766,6 +775,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();
let mut parent = Workspace::test_new("main");
@@ -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");