diff --git a/crates/recent_projects/src/recent_projects.rs b/crates/recent_projects/src/recent_projects.rs index 369cff1cc6..02a05f8929 100644 --- a/crates/recent_projects/src/recent_projects.rs +++ b/crates/recent_projects/src/recent_projects.rs @@ -17,7 +17,7 @@ use fs::Fs; #[cfg(target_os = "windows")] mod wsl_picker; -use remote::RemoteConnectionOptions; +use remote::{RemoteConnectionOptions, same_remote_connection_identity}; pub use remote_connection::{RemoteConnectionModal, connect, connect_with_modal}; pub use remote_connections::{navigate_to_positions, open_remote_project}; @@ -45,8 +45,8 @@ use ui::{ }; use util::{ResultExt, paths::PathExt}; use workspace::{ - HistoryManager, ModalView, MultiWorkspace, OpenMode, OpenOptions, OpenVisible, PathList, - RecentWorkspace, SerializedWorkspaceLocation, Workspace, WorkspaceDb, WorkspaceId, + HistoryManager, ModalView, MultiWorkspace, OpenMode, OpenOptions, OpenVisible, RecentWorkspace, + SerializedWorkspaceLocation, Workspace, WorkspaceDb, WorkspaceId, notifications::DetachAndPromptErr, with_active_or_new_workspace, }; use zed_actions::{OpenDevContainer, OpenRecent, OpenRemote}; @@ -2433,14 +2433,24 @@ impl RecentProjectsDelegate { .any(|key| key.matches(&workspace.project_group_key())) } - fn is_open_folder(&self, paths: &PathList) -> bool { + fn is_open_folder(&self, workspace: &RecentWorkspace) -> bool { if self.open_folders.is_empty() { return false; } - for workspace_path in paths.paths() { + let workspace_host = match &workspace.location { + SerializedWorkspaceLocation::Local => None, + SerializedWorkspaceLocation::Remote(options) => Some(options), + }; + + for workspace_path in workspace.paths.paths() { for open_folder in &self.open_folders { - if workspace_path == &open_folder.path { + if workspace_path == &open_folder.path + && same_remote_connection_identity( + workspace_host, + open_folder.connection_options.as_ref(), + ) + { return true; } } @@ -2456,7 +2466,7 @@ impl RecentProjectsDelegate { ) -> bool { !self.is_current_workspace(workspace.workspace_id, cx) && !self.is_in_current_window_groups(workspace) - && !self.is_open_folder(&workspace.paths) + && !self.is_open_folder(workspace) } } @@ -2467,7 +2477,7 @@ mod tests { use serde_json::json; use settings::SettingsStore; use util::path; - use workspace::{AppState, open_paths}; + use workspace::{AppState, PathList, open_paths}; use super::*; @@ -2679,6 +2689,53 @@ mod tests { ); } + #[gpui::test] + fn is_open_folder_distinguishes_local_and_remote(cx: &mut TestAppContext) { + init_test(cx); + + let shared_path = PathBuf::from("/repo"); + let local_open_folder = OpenFolderEntry { + worktree_id: WorktreeId::from_usize(0), + name: "repo".into(), + path: shared_path.clone(), + branch: None, + is_active: false, + connection_options: None, + }; + + let delegate = RecentProjectsDelegate::new( + WeakEntity::new_invalid(), + false, + cx.update(|cx| cx.focus_handle()), + vec![local_open_folder], + Vec::new(), + ProjectPickerStyle::Modal, + ); + + let paths = PathList::new(&[shared_path]); + let local_workspace = RecentWorkspace { + workspace_id: WorkspaceId::from_i64(1), + location: SerializedWorkspaceLocation::Local, + paths: paths.clone(), + identity_paths: paths.clone(), + timestamp: Utc::now(), + }; + let remote_workspace = RecentWorkspace { + workspace_id: WorkspaceId::from_i64(2), + location: SerializedWorkspaceLocation::Remote(RemoteConnectionOptions::Mock( + remote::MockConnectionOptions { id: 0 }, + )), + paths: paths.clone(), + identity_paths: paths, + timestamp: Utc::now(), + }; + + // A local open folder should hide only the matching local recent + // project, not a remote checkout that shares the same path. + assert!(delegate.is_open_folder(&local_workspace)); + assert!(!delegate.is_open_folder(&remote_workspace)); + } + #[gpui::test] fn deleting_top_recent_project_preserves_scroll_position(cx: &mut TestAppContext) { let target = FIRST_RECENT_PROJECT;