diff --git a/crates/project/src/git_store.rs b/crates/project/src/git_store.rs index 3e22857282bed51c703f3f7a7ee1b8af9a130bdb..fef9c0eeb39db1f04ac6a4318697bc1492126c09 100644 --- a/crates/project/src/git_store.rs +++ b/crates/project/src/git_store.rs @@ -6829,6 +6829,32 @@ pub fn worktrees_directory_for_repo( Ok(resolved) } +/// Returns a short name for a linked worktree suitable for UI display +/// +/// Uses the main worktree path to come up with a short name that disambiguates +/// the linked worktree from the main worktree. +pub fn linked_worktree_short_name( + main_worktree_path: &Path, + linked_worktree_path: &Path, +) -> Option { + if main_worktree_path == linked_worktree_path { + return None; + } + + let project_name = main_worktree_path.file_name()?.to_str()?; + let directory_name = linked_worktree_path.file_name()?.to_str()?; + let name = if directory_name != project_name { + directory_name.to_string() + } else { + linked_worktree_path + .parent()? + .file_name()? + .to_str()? + .to_string() + }; + Some(name.into()) +} + fn get_permalink_in_rust_registry_src( provider_registry: Arc, path: PathBuf, diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 9231a5ea97730cad1ade5fde181b5519c7163684..9ba5e9accd670a5aa4e1d449c445e83b84679676 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -47,7 +47,7 @@ pub use agent_server_store::{AgentId, AgentServerStore, AgentServersUpdated, Ext pub use git_store::{ ConflictRegion, ConflictSet, ConflictSetSnapshot, ConflictSetUpdate, git_traversal::{ChildEntriesGitIter, GitEntry, GitEntryRef, GitTraversal}, - worktrees_directory_for_repo, + linked_worktree_short_name, worktrees_directory_for_repo, }; pub use manifest_tree::ManifestTree; pub use project_search::{Search, SearchResults}; diff --git a/crates/project/tests/integration/git_store.rs b/crates/project/tests/integration/git_store.rs index 13cc16f0a0271e26ad5aac098325b1899734d51c..5476ed4c5b2edcf326a28fc39abdf6b1057cc59e 100644 --- a/crates/project/tests/integration/git_store.rs +++ b/crates/project/tests/integration/git_store.rs @@ -1539,7 +1539,7 @@ mod trust_tests { mod resolve_worktree_tests { use fs::FakeFs; use gpui::TestAppContext; - use project::git_store::resolve_git_worktree_to_main_repo; + use project::{git_store::resolve_git_worktree_to_main_repo, linked_worktree_short_name}; use serde_json::json; use std::path::{Path, PathBuf}; @@ -1616,4 +1616,32 @@ mod resolve_worktree_tests { resolve_git_worktree_to_main_repo(fs.as_ref(), Path::new("/does-not-exist")).await; assert_eq!(result, None); } + + #[test] + fn test_linked_worktree_short_name() { + let examples = [ + ( + "/home/bob/zed", + "/home/bob/worktrees/olivetti/zed", + Some("olivetti".into()), + ), + ("/home/bob/zed", "/home/bob/zed2", Some("zed2".into())), + ( + "/home/bob/zed", + "/home/bob/worktrees/zed/selectric", + Some("selectric".into()), + ), + ("/home/bob/zed", "/home/bob/zed", None), + ]; + for (main_worktree_path, linked_worktree_path, expected) in examples { + let short_name = linked_worktree_short_name( + Path::new(main_worktree_path), + Path::new(linked_worktree_path), + ); + assert_eq!( + short_name, expected, + "short name for {linked_worktree_path:?}, linked worktree of {main_worktree_path:?}, should be {expected:?}" + ); + } + } } diff --git a/crates/sidebar/src/sidebar.rs b/crates/sidebar/src/sidebar.rs index 9bd7838a020a5de81200c70f50836f33b1fdb7ed..9bd97406411ce1c0052dd84adc70e8073ad34e28 100644 --- a/crates/sidebar/src/sidebar.rs +++ b/crates/sidebar/src/sidebar.rs @@ -16,7 +16,7 @@ use gpui::{ use menu::{ Cancel, Confirm, SelectChild, SelectFirst, SelectLast, SelectNext, SelectParent, SelectPrevious, }; -use project::{AgentId, Event as ProjectEvent}; +use project::{AgentId, Event as ProjectEvent, linked_worktree_short_name}; use recent_projects::RecentProjects; use ui::utils::platform_title_bar_height; @@ -780,16 +780,16 @@ impl Sidebar { if snapshot.work_directory_abs_path != snapshot.original_repo_abs_path { continue; } + + let main_worktree_path = snapshot.original_repo_abs_path.clone(); + for git_worktree in snapshot.linked_worktrees() { - let name = git_worktree - .path - .file_name() - .unwrap_or_default() - .to_string_lossy() - .to_string(); + let worktree_name = + linked_worktree_short_name(&main_worktree_path, &git_worktree.path) + .unwrap_or_default(); linked_worktree_queries.push(( PathList::new(std::slice::from_ref(&git_worktree.path)), - name.into(), + worktree_name, Arc::from(git_worktree.path.as_path()), )); } diff --git a/crates/title_bar/src/title_bar.rs b/crates/title_bar/src/title_bar.rs index dd901a8a21c35958a5973c36cf764454e5090d21..5c3993f4e5a0e55fc49207f000633943ec50b5b5 100644 --- a/crates/title_bar/src/title_bar.rs +++ b/crates/title_bar/src/title_bar.rs @@ -14,6 +14,7 @@ pub use platform_title_bar::{ self, DraggedWindowTab, MergeAllWindows, MoveTabToNewWindow, PlatformTitleBar, ShowNextWindowTab, ShowPreviousWindowTab, }; +use project::linked_worktree_short_name; #[cfg(not(target_os = "macos"))] use crate::application_menu::{ @@ -173,21 +174,19 @@ impl Render for TitleBar { let mut repository = None; let mut linked_worktree_name = None; if let Some(worktree) = self.effective_active_worktree(cx) { + repository = self.get_repository_for_worktree(&worktree, cx); + let worktree = worktree.read(cx); project_name = worktree - .read(cx) .root_name() .file_name() .map(|name| SharedString::from(name.to_string())); - repository = self.get_repository_for_worktree(&worktree, cx); linked_worktree_name = repository.as_ref().and_then(|repo| { - let path = repo.read(cx).linked_worktree_path()?; - let directory_name = path.file_name()?.to_str()?; - let unique_worktree_name = if directory_name != project_name.as_ref()?.as_str() { - directory_name.to_string() - } else { - path.parent()?.file_name()?.to_str()?.to_string() - }; - Some(SharedString::from(unique_worktree_name)) + let repo = repo.read(cx); + linked_worktree_short_name( + repo.original_repo_abs_path.as_ref(), + repo.work_directory_abs_path.as_ref(), + ) + .filter(|name| Some(name) != project_name.as_ref()) }); }