diff options
| author | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-07-02 02:20:40 +0300 |
|---|---|---|
| committer | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-07-02 02:20:40 +0300 |
| commit | 48d58648aefcc59964a99be9c23778fe69346663 (patch) | |
| tree | cd982894e474bfd8b8ce7fbcb81d6487d7a7a064 /src/app/api | |
| parent | a9111cbab2a7550c7e84ec94c8b388de9a44daa3 (diff) | |
fix: follow cached cwd for new tabs
refs #912
Diffstat (limited to 'src/app/api')
| -rw-r--r-- | src/app/api/layouts.rs | 81 | ||||
| -rw-r--r-- | src/app/api/panes.rs | 9 | ||||
| -rw-r--r-- | src/app/api/tabs.rs | 72 |
3 files changed, 132 insertions, 30 deletions
diff --git a/src/app/api/layouts.rs b/src/app/api/layouts.rs index c7c02f5f..a2705acc 100644 --- a/src/app/api/layouts.rs +++ b/src/app/api/layouts.rs @@ -345,11 +345,9 @@ impl App { &self.terminal_runtimes, ) }); - self.resolve_new_terminal_cwd(follow_cwd.or_else(|| { - self.state - .focused_runtime_in_workspace(&self.terminal_runtimes, ws_idx) - .and_then(|runtime| runtime.cwd()) - })) + self.resolve_new_terminal_cwd( + follow_cwd.or_else(|| self.focused_pane_cwd_in_workspace(ws_idx)), + ) } fn apply_layout_node_to_pane( @@ -395,16 +393,11 @@ impl App { let default_shell = self.state.default_shell.clone(); let scrollback_limit_bytes = self.state.pane_scrollback_limit_bytes; let host_terminal_theme = self.state.host_terminal_theme; - let cwd = pane.cwd.as_ref().map(PathBuf::from).or_else(|| { - self.state.workspaces.get(ws_idx).and_then(|ws| { - let tab_idx = ws.find_tab_index_for_pane(target_pane_id)?; - ws.tabs.get(tab_idx)?.cwd_for_pane( - target_pane_id, - &self.state.terminals, - &self.terminal_runtimes, - ) - }) - }); + let cwd = pane + .cwd + .as_ref() + .map(PathBuf::from) + .or_else(|| self.cwd_for_pane_in_workspace(ws_idx, target_pane_id)); let extra_env = super::env::normalize_launch_env(pane.env.clone()) .map_err(|(_, message)| message.to_string())?; let direction = match direction { @@ -596,10 +589,20 @@ mod tests { use super::*; use crate::{ api::schema::{ErrorResponse, ResponseResult, SuccessResponse}, - config::Config, + config::{Config, ShellModeConfig}, workspace::Workspace, }; + #[cfg(windows)] + fn exiting_test_command() -> &'static str { + "C:\\Windows\\System32\\whoami.exe" + } + + #[cfg(not(windows))] + fn exiting_test_command() -> &'static str { + "/usr/bin/true" + } + fn app_with_workspace() -> App { let (_api_tx, api_rx) = tokio::sync::mpsc::unbounded_channel(); let mut app = App::new( @@ -609,6 +612,8 @@ mod tests { api_rx, crate::api::EventHub::default(), ); + app.state.default_shell = exiting_test_command().into(); + app.state.shell_mode = ShellModeConfig::NonLogin; app.state.workspaces = vec![Workspace::test_new("layout")]; app.state.active = Some(0); app.state.selected = 0; @@ -616,6 +621,13 @@ mod tests { app } + fn shutdown_test_runtimes(app: &mut App) { + let runtimes: Vec<_> = app.terminal_runtimes.drain().collect(); + for (_terminal_id, runtime) in runtimes { + runtime.shutdown(); + } + } + #[test] fn layout_export_returns_portable_tree() { let mut app = app_with_workspace(); @@ -779,6 +791,43 @@ mod tests { second_pane.command, Some(vec!["sh".into(), "-c".into(), "true".into()]) ); + shutdown_test_runtimes(&mut app); + } + + #[tokio::test] + async fn layout_apply_new_tab_follows_cached_focused_pane_cwd_without_runtime() { + let mut app = app_with_workspace(); + let focused_pane = app.state.workspaces[0].tabs[0].root_pane; + let cached_cwd = std::env::temp_dir(); + let terminal_id = app.state.workspaces[0] + .terminal_id(focused_pane) + .cloned() + .unwrap(); + app.state.terminals.get_mut(&terminal_id).unwrap().cwd = cached_cwd.clone(); + + let response = app.handle_layout_apply( + "req".into(), + LayoutApplyParams { + workspace_id: None, + tab_id: None, + tab_label: Some("cached".into()), + focus: false, + root: LayoutNode::Pane { + pane: LayoutPane::default(), + }, + }, + ); + + let success: SuccessResponse = serde_json::from_str(&response).unwrap(); + assert!(matches!(success.result, ResponseResult::LayoutApply { .. })); + let created = &app.state.workspaces[0].tabs[1]; + let created_terminal_id = created.terminal_id(created.root_pane).unwrap(); + let created_cwd = &app.state.terminals.get(created_terminal_id).unwrap().cwd; + assert_eq!( + crate::worktree::canonical_or_original(created_cwd), + crate::worktree::canonical_or_original(&cached_cwd) + ); + shutdown_test_runtimes(&mut app); } #[tokio::test] diff --git a/src/app/api/panes.rs b/src/app/api/panes.rs index 5723be1e..a0428b27 100644 --- a/src/app/api/panes.rs +++ b/src/app/api/panes.rs @@ -51,14 +51,7 @@ impl App { }; let (rows, cols) = self.state.estimate_pane_size(); let split_cwd = params.cwd.map(std::path::PathBuf::from).or_else(|| { - let follow_cwd = self.state.workspaces.get(ws_idx).and_then(|ws| { - let tab_idx = ws.find_tab_index_for_pane(target_pane_id)?; - ws.tabs.get(tab_idx)?.cwd_for_pane( - target_pane_id, - &self.state.terminals, - &self.terminal_runtimes, - ) - }); + let follow_cwd = self.cwd_for_pane_in_workspace(ws_idx, target_pane_id); Some(self.resolve_new_terminal_cwd(follow_cwd)) }); let default_shell = self.state.default_shell.clone(); diff --git a/src/app/api/tabs.rs b/src/app/api/tabs.rs index abd05b29..ce126ca7 100644 --- a/src/app/api/tabs.rs +++ b/src/app/api/tabs.rs @@ -63,11 +63,7 @@ impl App { return encode_error(id, "workspace_not_found", "no active workspace"); }; let cwd = cwd.map(PathBuf::from).unwrap_or_else(|| { - let follow_cwd = self - .state - .focused_runtime_in_workspace(&self.terminal_runtimes, ws_idx) - .and_then(|rt| rt.cwd()); - self.resolve_new_terminal_cwd(follow_cwd) + self.resolve_new_terminal_cwd(self.focused_pane_cwd_in_workspace(ws_idx)) }); let (rows, cols) = self.state.estimate_pane_size(); let default_shell = self.state.default_shell.clone(); @@ -297,7 +293,28 @@ fn tab_not_found(id: String, tab_id: &str) -> String { #[cfg(test)] mod tests { use super::*; - use crate::{api::schema::SuccessResponse, config::Config, workspace::Workspace}; + use crate::{ + api::schema::SuccessResponse, + config::{Config, ShellModeConfig}, + workspace::Workspace, + }; + + #[cfg(windows)] + fn exiting_test_command() -> &'static str { + "C:\\Windows\\System32\\whoami.exe" + } + + #[cfg(not(windows))] + fn exiting_test_command() -> &'static str { + "/usr/bin/true" + } + + fn shutdown_test_runtimes(app: &mut App) { + let runtimes: Vec<_> = app.terminal_runtimes.drain().collect(); + for (_terminal_id, runtime) in runtimes { + runtime.shutdown(); + } + } #[test] fn api_tab_move_reorders_tabs_in_target_workspace() { @@ -342,4 +359,47 @@ mod tests { ) })); } + + #[tokio::test] + async fn tab_create_follows_cached_focused_pane_cwd_without_runtime() { + let event_hub = crate::api::EventHub::default(); + let (_api_tx, api_rx) = tokio::sync::mpsc::unbounded_channel(); + let mut app = App::new(&Config::default(), true, None, api_rx, event_hub); + app.state.default_shell = exiting_test_command().into(); + app.state.shell_mode = ShellModeConfig::NonLogin; + let workspace = Workspace::test_new("tabs"); + let focused_pane = workspace.tabs[0].root_pane; + app.state.workspaces = vec![workspace]; + app.state.active = Some(0); + app.state.selected = 0; + app.state.ensure_test_terminals(); + let cached_cwd = std::env::temp_dir(); + let terminal_id = app.state.workspaces[0] + .terminal_id(focused_pane) + .cloned() + .unwrap(); + app.state.terminals.get_mut(&terminal_id).unwrap().cwd = cached_cwd.clone(); + + let response = app.handle_tab_create( + "req".into(), + TabCreateParams { + workspace_id: None, + cwd: None, + focus: false, + label: None, + env: Default::default(), + }, + ); + + let success: SuccessResponse = serde_json::from_str(&response).unwrap(); + assert!(matches!(success.result, ResponseResult::TabCreated { .. })); + let created = &app.state.workspaces[0].tabs[1]; + let created_terminal_id = created.terminal_id(created.root_pane).unwrap(); + let created_cwd = &app.state.terminals.get(created_terminal_id).unwrap().cwd; + assert_eq!( + crate::worktree::canonical_or_original(created_cwd), + crate::worktree::canonical_or_original(&cached_cwd) + ); + shutdown_test_runtimes(&mut app); + } } |
