From b0fd10134f27690d449fad18323f6da299b3db31 Mon Sep 17 00:00:00 2001 From: Giorgi Merebashvili Date: Mon, 16 Mar 2026 17:27:41 +0400 Subject: [PATCH] file_finder: Fix project root appearing in file paths while searching when hide_root=true (#51530) Closes #45135 Before you mark this PR as ready for review, make sure that you have: - [x] Added a solid test coverage and/or screenshots from doing manual testing - [x] Done a self-review taking into account security and performance aspects - [x] Aligned any UI changes with the [UI checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) Release Notes: - Fixed project root name appearing in file paths while searching in file finder. --- crates/file_finder/src/file_finder.rs | 58 +++++----- crates/file_finder/src/file_finder_tests.rs | 113 ++++++++++++++++++++ 2 files changed, 143 insertions(+), 28 deletions(-) diff --git a/crates/file_finder/src/file_finder.rs b/crates/file_finder/src/file_finder.rs index 7e0c584c739caa9c71f87be9673a04bd9b9b840f..3dcd052c34acc3a28650c58079c82499b7e94c85 100644 --- a/crates/file_finder/src/file_finder.rs +++ b/crates/file_finder/src/file_finder.rs @@ -563,18 +563,21 @@ impl Matches { .extend(history_items.into_iter().map(path_to_entry)); return; }; - // If several worktress are open we have to set the worktree root names in path prefix - let several_worktrees = worktree_store.read(cx).worktrees().count() > 1; - let worktree_name_by_id = several_worktrees.then(|| { - worktree_store - .read(cx) - .worktrees() - .map(|worktree| { - let snapshot = worktree.read(cx).snapshot(); - (snapshot.id(), snapshot.root_name().into()) - }) - .collect() - }); + + let worktree_name_by_id = if should_hide_root_in_entry_path(&worktree_store, cx) { + None + } else { + Some( + worktree_store + .read(cx) + .worktrees() + .map(|worktree| { + let snapshot = worktree.read(cx).snapshot(); + (snapshot.id(), snapshot.root_name().into()) + }) + .collect(), + ) + }; let new_history_matches = matching_history_items( history_items, currently_opened, @@ -797,6 +800,16 @@ fn matching_history_items<'a>( matching_history_paths } +fn should_hide_root_in_entry_path(worktree_store: &Entity, cx: &App) -> bool { + let multiple_worktrees = worktree_store + .read(cx) + .visible_worktrees(cx) + .filter(|worktree| !worktree.read(cx).is_single_file()) + .nth(1) + .is_some(); + ProjectPanelSettings::get_global(cx).hide_root && !multiple_worktrees +} + #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] struct FoundPath { project: ProjectPath, @@ -902,14 +915,12 @@ impl FileFinderDelegate { .currently_opened_path .as_ref() .map(|found_path| Arc::clone(&found_path.project.path)); - let worktrees = self - .project - .read(cx) - .worktree_store() + let worktree_store = self.project.read(cx).worktree_store(); + let worktrees = worktree_store .read(cx) .visible_worktrees_and_single_files(cx) .collect::>(); - let include_root_name = worktrees.len() > 1; + let include_root_name = !should_hide_root_in_entry_path(&worktree_store, cx); let candidate_sets = worktrees .into_iter() .map(|worktree| { @@ -1135,17 +1146,8 @@ impl FileFinderDelegate { if let Some(panel_match) = panel_match { self.labels_for_path_match(&panel_match.0, path_style) } else if let Some(worktree) = worktree { - let multiple_folders_open = self - .project - .read(cx) - .visible_worktrees(cx) - .filter(|worktree| !worktree.read(cx).is_single_file()) - .nth(1) - .is_some(); - - let full_path = if ProjectPanelSettings::get_global(cx).hide_root - && !multiple_folders_open - { + let worktree_store = self.project.read(cx).worktree_store(); + let full_path = if should_hide_root_in_entry_path(&worktree_store, cx) { entry_path.project.path.clone() } else { worktree.read(cx).root_name().join(&entry_path.project.path) diff --git a/crates/file_finder/src/file_finder_tests.rs b/crates/file_finder/src/file_finder_tests.rs index da9fd4b87b045a6321a291cb7128a051d977815b..cd9f22ef9e9c09a828ceced449ebafb9c3c2e12b 100644 --- a/crates/file_finder/src/file_finder_tests.rs +++ b/crates/file_finder/src/file_finder_tests.rs @@ -400,6 +400,18 @@ async fn test_absolute_paths(cx: &mut TestAppContext) { #[gpui::test] async fn test_complex_path(cx: &mut TestAppContext) { let app_state = init_test(cx); + + cx.update(|cx| { + let settings = *ProjectPanelSettings::get_global(cx); + ProjectPanelSettings::override_global( + ProjectPanelSettings { + hide_root: true, + ..settings + }, + cx, + ); + }); + app_state .fs .as_fake() @@ -1413,6 +1425,18 @@ async fn test_create_file_no_focused_with_multiple_worktrees(cx: &mut TestAppCon #[gpui::test] async fn test_path_distance_ordering(cx: &mut TestAppContext) { let app_state = init_test(cx); + + cx.update(|cx| { + let settings = *ProjectPanelSettings::get_global(cx); + ProjectPanelSettings::override_global( + ProjectPanelSettings { + hide_root: true, + ..settings + }, + cx, + ); + }); + app_state .fs .as_fake() @@ -1648,6 +1672,17 @@ async fn test_query_history(cx: &mut gpui::TestAppContext) { async fn test_history_match_positions(cx: &mut gpui::TestAppContext) { let app_state = init_test(cx); + cx.update(|cx| { + let settings = *ProjectPanelSettings::get_global(cx); + ProjectPanelSettings::override_global( + ProjectPanelSettings { + hide_root: true, + ..settings + }, + cx, + ); + }); + app_state .fs .as_fake() @@ -2148,6 +2183,17 @@ async fn test_toggle_panel_new_selections(cx: &mut gpui::TestAppContext) { async fn test_search_preserves_history_items(cx: &mut gpui::TestAppContext) { let app_state = init_test(cx); + cx.update(|cx| { + let settings = *ProjectPanelSettings::get_global(cx); + ProjectPanelSettings::override_global( + ProjectPanelSettings { + hide_root: true, + ..settings + }, + cx, + ); + }); + app_state .fs .as_fake() @@ -2253,6 +2299,17 @@ async fn test_search_preserves_history_items(cx: &mut gpui::TestAppContext) { async fn test_search_sorts_history_items(cx: &mut gpui::TestAppContext) { let app_state = init_test(cx); + cx.update(|cx| { + let settings = *ProjectPanelSettings::get_global(cx); + ProjectPanelSettings::override_global( + ProjectPanelSettings { + hide_root: true, + ..settings + }, + cx, + ); + }); + app_state .fs .as_fake() @@ -2736,6 +2793,17 @@ async fn test_selected_history_item_stays_selected_on_worktree_updated(cx: &mut async fn test_history_items_vs_very_good_external_match(cx: &mut gpui::TestAppContext) { let app_state = init_test(cx); + cx.update(|cx| { + let settings = *ProjectPanelSettings::get_global(cx); + ProjectPanelSettings::override_global( + ProjectPanelSettings { + hide_root: true, + ..settings + }, + cx, + ); + }); + app_state .fs .as_fake() @@ -2784,6 +2852,17 @@ async fn test_history_items_vs_very_good_external_match(cx: &mut gpui::TestAppCo async fn test_nonexistent_history_items_not_shown(cx: &mut gpui::TestAppContext) { let app_state = init_test(cx); + cx.update(|cx| { + let settings = *ProjectPanelSettings::get_global(cx); + ProjectPanelSettings::override_global( + ProjectPanelSettings { + hide_root: true, + ..settings + }, + cx, + ); + }); + app_state .fs .as_fake() @@ -3183,6 +3262,17 @@ async fn test_history_items_uniqueness_for_multiple_worktree_open_all_files( async fn test_selected_match_stays_selected_after_matches_refreshed(cx: &mut gpui::TestAppContext) { let app_state = init_test(cx); + cx.update(|cx| { + let settings = *ProjectPanelSettings::get_global(cx); + ProjectPanelSettings::override_global( + ProjectPanelSettings { + hide_root: true, + ..settings + }, + cx, + ); + }); + app_state.fs.as_fake().insert_tree("/src", json!({})).await; app_state @@ -3779,6 +3869,17 @@ fn assert_match_at_position( async fn test_filename_precedence(cx: &mut TestAppContext) { let app_state = init_test(cx); + cx.update(|cx| { + let settings = *ProjectPanelSettings::get_global(cx); + ProjectPanelSettings::override_global( + ProjectPanelSettings { + hide_root: true, + ..settings + }, + cx, + ); + }); + app_state .fs .as_fake() @@ -3823,6 +3924,18 @@ async fn test_filename_precedence(cx: &mut TestAppContext) { #[gpui::test] async fn test_paths_with_starting_slash(cx: &mut TestAppContext) { let app_state = init_test(cx); + + cx.update(|cx| { + let settings = *ProjectPanelSettings::get_global(cx); + ProjectPanelSettings::override_global( + ProjectPanelSettings { + hide_root: true, + ..settings + }, + cx, + ); + }); + app_state .fs .as_fake()