Parse `./`/`a/`/`b/`-prefixed paths more leniently in the file finder (#31459)

Kirill Bulatov created

Closes https://github.com/zed-industries/zed/issues/15081
Closes https://github.com/zed-industries/zed/issues/31064

Release Notes:

- Parse `./`/`a/`/`b/`-prefixed paths more leniently in the file finder

Change summary

crates/file_finder/src/file_finder.rs       | 42 +++++++++++++++++++++++
crates/file_finder/src/file_finder_tests.rs |  8 +++
2 files changed, 49 insertions(+), 1 deletion(-)

Detailed changes

crates/file_finder/src/file_finder.rs 🔗

@@ -1170,6 +1170,48 @@ impl PickerDelegate for FileFinderDelegate {
     ) -> Task<()> {
         let raw_query = raw_query.replace(' ', "");
         let raw_query = raw_query.trim();
+
+        let raw_query = match &raw_query.get(0..2) {
+            Some(".\\") | Some("./") => &raw_query[2..],
+            Some("a\\") | Some("a/") => {
+                if self
+                    .workspace
+                    .upgrade()
+                    .into_iter()
+                    .flat_map(|workspace| workspace.read(cx).worktrees(cx))
+                    .all(|worktree| {
+                        worktree
+                            .read(cx)
+                            .entry_for_path(Path::new("a"))
+                            .is_none_or(|entry| !entry.is_dir())
+                    })
+                {
+                    &raw_query[2..]
+                } else {
+                    raw_query
+                }
+            }
+            Some("b\\") | Some("b/") => {
+                if self
+                    .workspace
+                    .upgrade()
+                    .into_iter()
+                    .flat_map(|workspace| workspace.read(cx).worktrees(cx))
+                    .all(|worktree| {
+                        worktree
+                            .read(cx)
+                            .entry_for_path(Path::new("b"))
+                            .is_none_or(|entry| !entry.is_dir())
+                    })
+                {
+                    &raw_query[2..]
+                } else {
+                    raw_query
+                }
+            }
+            _ => raw_query,
+        };
+
         if raw_query.is_empty() {
             // if there was no query before, and we already have some (history) matches
             // there's no need to update anything, since nothing has changed.

crates/file_finder/src/file_finder_tests.rs 🔗

@@ -206,6 +206,11 @@ async fn test_matching_paths(cx: &mut TestAppContext) {
 
     for bandana_query in [
         "bandana",
+        "./bandana",
+        ".\\bandana",
+        util::separator!("a/bandana"),
+        "b/bandana",
+        "b\\bandana",
         " bandana",
         "bandana ",
         " bandana ",
@@ -224,7 +229,8 @@ async fn test_matching_paths(cx: &mut TestAppContext) {
             assert_eq!(
                 picker.delegate.matches.len(),
                 1,
-                "Wrong number of matches for bandana query '{bandana_query}'"
+                "Wrong number of matches for bandana query '{bandana_query}'. Matches: {:?}",
+                picker.delegate.matches
             );
         });
         cx.dispatch_action(SelectNext);