Skip to content

file_finder: Fix path duplication when opening non-project files with a filter - #54944

Merged
yara-blue merged 3 commits into
zed-industries:mainfrom
saberoueslati:file_finder/fix-single-file-worktree-path-duplication
Jun 2, 2026
Merged

file_finder: Fix path duplication when opening non-project files with a filter#54944
yara-blue merged 3 commits into
zed-industries:mainfrom
saberoueslati:file_finder/fix-single-file-worktree-path-duplication

Conversation

@saberoueslati

@saberoueslati saberoueslati commented Apr 27, 2026

Copy link
Copy Markdown
Contributor

Context

When a file is opened outside any project, Zed creates a single-file worktree for it where the file's relative path is "" (the worktree root IS the file). Typing to filter in the file picker (Ctrl-P) caused a crash: Error: opening project path "/home/user/foo.txt/foo.txt".

Two bugs combined to produce this:

  1. History lookup mismatch : fuzzy_nucleo detects root_is_file = true for single-file worktrees and moves the worktree root name into path_match.path (so "" → "foo.txt"). matching_history_items stored the entry under key ""but looked it up by "foo.txt" → miss → item dropped from history matches.

  2. Search confirm duplication : because the history match was dropped, the file appeared as Match::Search with path_match.path = "foo.txt". Confirming the constructed ProjectPath { path: "foo.txt" } inside a worktree rooted at /home/user/foo.txt → resolved to /home/user/foo.txt/foo.txt.

Fix 1 adds a fallback empty-path lookup in matching_history_items so single-file worktree entries are found correctly and deduplication suppresses the search duplicate. Fix 2 is defense-in-depth: if a single-file worktree file ever reaches
the Match::Search confirm handler, it detects is_single_file() and uses an empty path instead.

Edit :

After further work, two additional edge cases were fixed:

  • Match::Search split-open handling now uses the same single-file worktree path normalization as normal confirm. This prevents split-opening a single-file worktree search result from resolving notes.txt inside /path/to/notes.txt as /path/to/notes.txt/notes.txt.

  • History matching now still includes root names for single-file worktrees when project_panel.hide_root = true. Normal folder worktree roots remain hidden in this mode, but single-file worktrees need their root name included because the root name is the filename users type into the picker.

Additional test coverage:

  • Added test_non_project_file_matches_history_with_hidden_root for the hide_root=true history matching edge case.
  • Added test_single_file_search_result_split_open for split-opening a single-file worktree search result.

Closes #54934

Manual test after fix below :

Screencast.from.2026-04-26.23-58-00.webm

How to Review

  • crates/file_finder/src/file_finder.rs : Two targeted changes:

    • matching_history_items (~line 757): added .or_else fallback that retries the candidates lookup with an empty path when the first lookup misses, covering the root_is_file key mismatch for single-file worktrees.
    • Match::Search confirm handler (~line 1640): checks wt.read(cx).is_single_file() and substitutes RelPath::empty() for path_match.path to prevent duplication.
  • crates/file_finder/src/file_finder_tests.rs — Two test changes:

    • New test test_non_project_file_open_with_filter: opens a file outside the project, filters for it by name, confirms, and asserts the correct path is opened.
    • Updated test_search_results_refreshed_on_standalone_file_creation: the fix correctly promotes single-file worktree files to Match::History, which activates skip_focus_for_active_in_search when the file is currently open. The test now asserts the match type directly and closes the picker with menu::Cancel instead of confirming.

Self-Review Checklist

  • I've reviewed my own diff for quality, security, and reliability
  • Unsafe blocks (if any) have justifying comments
  • The content is consistent with the UI/UX checklist
  • Tests cover the new/changed behavior
  • Performance impact has been considered and is acceptable

Release Notes:

  • Fixed file picker failing to open non-project files when a filter is typed

@cla-bot cla-bot Bot added the cla-signed The user has signed the Contributor License Agreement label Apr 27, 2026
@Veykril Veykril self-assigned this Apr 27, 2026
@saberoueslati
saberoueslati force-pushed the file_finder/fix-single-file-worktree-path-duplication branch from 0eb6912 to 79943a7 Compare April 28, 2026 11:24
@saberoueslati

Copy link
Copy Markdown
Contributor Author

@ChristopherBiscardi can you run the CI/CD pipeline for this PR ? Thank you

@Veykril Veykril removed their assignment May 4, 2026
@yara-blue

Copy link
Copy Markdown
Contributor

Hi @saberoueslati sorry it took so long to get to this, now it unfortunately got a merge conflict. Could you adress that? Feel free to ping me when that is done!

@yara-blue yara-blue self-assigned this Jun 1, 2026
@saberoueslati
saberoueslati force-pushed the file_finder/fix-single-file-worktree-path-duplication branch from a16893a to 8115d22 Compare June 1, 2026 22:05
@saberoueslati

Copy link
Copy Markdown
Contributor Author

@yara-blue thank you, conflict is resolved now

@yara-blue
yara-blue added this pull request to the merge queue Jun 2, 2026
@yara-blue

Copy link
Copy Markdown
Contributor

Thank you! looks great :)

Merged via the queue into zed-industries:main with commit 6ac8385 Jun 2, 2026
32 checks passed
dandv pushed a commit to dandv/zed that referenced this pull request Jun 3, 2026
… a filter (zed-industries#54944)

## Context

When a file is opened outside any project, Zed creates a single-file
worktree for it where the file's relative path is `""` (the worktree
root IS the file). Typing to filter in the file picker (Ctrl-P) caused a
crash: `Error: opening project path
"/home/user/foo.txt/foo.txt"`.

Two bugs combined to produce this:

1. **History lookup mismatch** : `fuzzy_nucleo` detects `root_is_file =
true` for single-file worktrees and moves the worktree root name into
`path_match.path` (so `"" → "foo.txt"`). `matching_history_items` stored
the entry under key `""`but looked it up by `"foo.txt"` → miss → item
dropped from history matches.

2. **Search confirm duplication** : because the history match was
dropped, the file appeared as `Match::Search` with `path_match.path =
"foo.txt"`. Confirming the constructed `ProjectPath { path: "foo.txt" }`
inside a worktree rooted at `/home/user/foo.txt` → resolved to
`/home/user/foo.txt/foo.txt`.

Fix 1 adds a fallback empty-path lookup in `matching_history_items` so
single-file worktree entries are found correctly and deduplication
suppresses the search duplicate. Fix 2 is defense-in-depth: if a
single-file worktree file ever reaches
the `Match::Search` confirm handler, it detects `is_single_file()` and
uses an empty path instead.

**Edit :**

After further work, two additional edge cases were fixed:

- `Match::Search` split-open handling now uses the same single-file
worktree path normalization as normal confirm. This prevents
split-opening a single-file worktree search result from resolving
`notes.txt` inside `/path/to/notes.txt` as
`/path/to/notes.txt/notes.txt`.

- History matching now still includes root names for single-file
worktrees when `project_panel.hide_root = true`. Normal folder worktree
roots remain hidden in this mode, but single-file worktrees need their
root name included because the root name is the filename users type into
the picker.

Additional test coverage:

- Added `test_non_project_file_matches_history_with_hidden_root` for the
`hide_root=true` history matching edge case.
- Added `test_single_file_search_result_split_open` for split-opening a
single-file worktree search result.

Closes zed-industries#54934

Manual test after fix below :

[Screencast from 2026-04-26
23-58-00.webm](https://github.com/user-attachments/assets/3de564d8-cc94-4624-98e3-54dd124bfa2f)

## How to Review

- `crates/file_finder/src/file_finder.rs` : Two targeted changes: 
- `matching_history_items` (~line 757): added `.or_else` fallback that
retries the candidates lookup with an empty path when the first lookup
misses, covering the `root_is_file` key mismatch for single-file
worktrees.
- `Match::Search` confirm handler (~line 1640): checks
`wt.read(cx).is_single_file()` and substitutes `RelPath::empty()` for
`path_match.path` to prevent duplication.

- `crates/file_finder/src/file_finder_tests.rs` — Two test changes:
- New test `test_non_project_file_open_with_filter`: opens a file
outside the project, filters for it by name, confirms, and asserts the
correct path is opened.
- Updated `test_search_results_refreshed_on_standalone_file_creation`:
the fix correctly promotes single-file worktree files to
`Match::History`, which activates `skip_focus_for_active_in_search` when
the file is currently open. The test now asserts the match type directly
and closes the picker with `menu::Cancel` instead of confirming.

## Self-Review Checklist

- [x] I've reviewed my own diff for quality, security, and reliability
- [ ] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the UI/UX checklist
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

Release Notes:

- Fixed file picker failing to open non-project files when a filter is
typed
TomPlanche pushed a commit to TomPlanche/zed that referenced this pull request Jun 8, 2026
… a filter (zed-industries#54944)

## Context

When a file is opened outside any project, Zed creates a single-file
worktree for it where the file's relative path is `""` (the worktree
root IS the file). Typing to filter in the file picker (Ctrl-P) caused a
crash: `Error: opening project path
"/home/user/foo.txt/foo.txt"`.

Two bugs combined to produce this:

1. **History lookup mismatch** : `fuzzy_nucleo` detects `root_is_file =
true` for single-file worktrees and moves the worktree root name into
`path_match.path` (so `"" → "foo.txt"`). `matching_history_items` stored
the entry under key `""`but looked it up by `"foo.txt"` → miss → item
dropped from history matches.

2. **Search confirm duplication** : because the history match was
dropped, the file appeared as `Match::Search` with `path_match.path =
"foo.txt"`. Confirming the constructed `ProjectPath { path: "foo.txt" }`
inside a worktree rooted at `/home/user/foo.txt` → resolved to
`/home/user/foo.txt/foo.txt`.

Fix 1 adds a fallback empty-path lookup in `matching_history_items` so
single-file worktree entries are found correctly and deduplication
suppresses the search duplicate. Fix 2 is defense-in-depth: if a
single-file worktree file ever reaches
the `Match::Search` confirm handler, it detects `is_single_file()` and
uses an empty path instead.

**Edit :**

After further work, two additional edge cases were fixed:

- `Match::Search` split-open handling now uses the same single-file
worktree path normalization as normal confirm. This prevents
split-opening a single-file worktree search result from resolving
`notes.txt` inside `/path/to/notes.txt` as
`/path/to/notes.txt/notes.txt`.

- History matching now still includes root names for single-file
worktrees when `project_panel.hide_root = true`. Normal folder worktree
roots remain hidden in this mode, but single-file worktrees need their
root name included because the root name is the filename users type into
the picker.

Additional test coverage:

- Added `test_non_project_file_matches_history_with_hidden_root` for the
`hide_root=true` history matching edge case.
- Added `test_single_file_search_result_split_open` for split-opening a
single-file worktree search result.

Closes zed-industries#54934

Manual test after fix below :

[Screencast from 2026-04-26
23-58-00.webm](https://github.com/user-attachments/assets/3de564d8-cc94-4624-98e3-54dd124bfa2f)

## How to Review

- `crates/file_finder/src/file_finder.rs` : Two targeted changes: 
- `matching_history_items` (~line 757): added `.or_else` fallback that
retries the candidates lookup with an empty path when the first lookup
misses, covering the `root_is_file` key mismatch for single-file
worktrees.
- `Match::Search` confirm handler (~line 1640): checks
`wt.read(cx).is_single_file()` and substitutes `RelPath::empty()` for
`path_match.path` to prevent duplication.

- `crates/file_finder/src/file_finder_tests.rs` — Two test changes:
- New test `test_non_project_file_open_with_filter`: opens a file
outside the project, filters for it by name, confirms, and asserts the
correct path is opened.
- Updated `test_search_results_refreshed_on_standalone_file_creation`:
the fix correctly promotes single-file worktree files to
`Match::History`, which activates `skip_focus_for_active_in_search` when
the file is currently open. The test now asserts the match type directly
and closes the picker with `menu::Cancel` instead of confirming.

## Self-Review Checklist

- [x] I've reviewed my own diff for quality, security, and reliability
- [ ] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the UI/UX checklist
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

Release Notes:

- Fixed file picker failing to open non-project files when a filter is
typed
This was referenced Jun 18, 2026
jonx pushed a commit to jonx/zed-aros that referenced this pull request Jul 17, 2026
… a filter (zed-industries#54944)

## Context

When a file is opened outside any project, Zed creates a single-file
worktree for it where the file's relative path is `""` (the worktree
root IS the file). Typing to filter in the file picker (Ctrl-P) caused a
crash: `Error: opening project path
"/home/user/foo.txt/foo.txt"`.

Two bugs combined to produce this:

1. **History lookup mismatch** : `fuzzy_nucleo` detects `root_is_file =
true` for single-file worktrees and moves the worktree root name into
`path_match.path` (so `"" → "foo.txt"`). `matching_history_items` stored
the entry under key `""`but looked it up by `"foo.txt"` → miss → item
dropped from history matches.

2. **Search confirm duplication** : because the history match was
dropped, the file appeared as `Match::Search` with `path_match.path =
"foo.txt"`. Confirming the constructed `ProjectPath { path: "foo.txt" }`
inside a worktree rooted at `/home/user/foo.txt` → resolved to
`/home/user/foo.txt/foo.txt`.

Fix 1 adds a fallback empty-path lookup in `matching_history_items` so
single-file worktree entries are found correctly and deduplication
suppresses the search duplicate. Fix 2 is defense-in-depth: if a
single-file worktree file ever reaches
the `Match::Search` confirm handler, it detects `is_single_file()` and
uses an empty path instead.

**Edit :**

After further work, two additional edge cases were fixed:

- `Match::Search` split-open handling now uses the same single-file
worktree path normalization as normal confirm. This prevents
split-opening a single-file worktree search result from resolving
`notes.txt` inside `/path/to/notes.txt` as
`/path/to/notes.txt/notes.txt`.

- History matching now still includes root names for single-file
worktrees when `project_panel.hide_root = true`. Normal folder worktree
roots remain hidden in this mode, but single-file worktrees need their
root name included because the root name is the filename users type into
the picker.

Additional test coverage:

- Added `test_non_project_file_matches_history_with_hidden_root` for the
`hide_root=true` history matching edge case.
- Added `test_single_file_search_result_split_open` for split-opening a
single-file worktree search result.

Closes zed-industries#54934

Manual test after fix below :

[Screencast from 2026-04-26
23-58-00.webm](https://github.com/user-attachments/assets/3de564d8-cc94-4624-98e3-54dd124bfa2f)

## How to Review

- `crates/file_finder/src/file_finder.rs` : Two targeted changes: 
- `matching_history_items` (~line 757): added `.or_else` fallback that
retries the candidates lookup with an empty path when the first lookup
misses, covering the `root_is_file` key mismatch for single-file
worktrees.
- `Match::Search` confirm handler (~line 1640): checks
`wt.read(cx).is_single_file()` and substitutes `RelPath::empty()` for
`path_match.path` to prevent duplication.

- `crates/file_finder/src/file_finder_tests.rs` — Two test changes:
- New test `test_non_project_file_open_with_filter`: opens a file
outside the project, filters for it by name, confirms, and asserts the
correct path is opened.
- Updated `test_search_results_refreshed_on_standalone_file_creation`:
the fix correctly promotes single-file worktree files to
`Match::History`, which activates `skip_focus_for_active_in_search` when
the file is currently open. The test now asserts the match type directly
and closes the picker with `menu::Cancel` instead of confirming.

## Self-Review Checklist

- [x] I've reviewed my own diff for quality, security, and reliability
- [ ] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the UI/UX checklist
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

Release Notes:

- Fixed file picker failing to open non-project files when a filter is
typed
@yara-blue yara-blue removed their assignment Aug 3, 2026
jolutz pushed a commit to jolutz/zed that referenced this pull request Aug 8, 2026
… a filter (zed-industries#54944)

## Context

When a file is opened outside any project, Zed creates a single-file
worktree for it where the file's relative path is `""` (the worktree
root IS the file). Typing to filter in the file picker (Ctrl-P) caused a
crash: `Error: opening project path
"/home/user/foo.txt/foo.txt"`.

Two bugs combined to produce this:

1. **History lookup mismatch** : `fuzzy_nucleo` detects `root_is_file =
true` for single-file worktrees and moves the worktree root name into
`path_match.path` (so `"" → "foo.txt"`). `matching_history_items` stored
the entry under key `""`but looked it up by `"foo.txt"` → miss → item
dropped from history matches.

2. **Search confirm duplication** : because the history match was
dropped, the file appeared as `Match::Search` with `path_match.path =
"foo.txt"`. Confirming the constructed `ProjectPath { path: "foo.txt" }`
inside a worktree rooted at `/home/user/foo.txt` → resolved to
`/home/user/foo.txt/foo.txt`.

Fix 1 adds a fallback empty-path lookup in `matching_history_items` so
single-file worktree entries are found correctly and deduplication
suppresses the search duplicate. Fix 2 is defense-in-depth: if a
single-file worktree file ever reaches
the `Match::Search` confirm handler, it detects `is_single_file()` and
uses an empty path instead.

**Edit :**

After further work, two additional edge cases were fixed:

- `Match::Search` split-open handling now uses the same single-file
worktree path normalization as normal confirm. This prevents
split-opening a single-file worktree search result from resolving
`notes.txt` inside `/path/to/notes.txt` as
`/path/to/notes.txt/notes.txt`.

- History matching now still includes root names for single-file
worktrees when `project_panel.hide_root = true`. Normal folder worktree
roots remain hidden in this mode, but single-file worktrees need their
root name included because the root name is the filename users type into
the picker.

Additional test coverage:

- Added `test_non_project_file_matches_history_with_hidden_root` for the
`hide_root=true` history matching edge case.
- Added `test_single_file_search_result_split_open` for split-opening a
single-file worktree search result.

Closes zed-industries#54934

Manual test after fix below :

[Screencast from 2026-04-26
23-58-00.webm](https://github.com/user-attachments/assets/3de564d8-cc94-4624-98e3-54dd124bfa2f)

## How to Review

- `crates/file_finder/src/file_finder.rs` : Two targeted changes: 
- `matching_history_items` (~line 757): added `.or_else` fallback that
retries the candidates lookup with an empty path when the first lookup
misses, covering the `root_is_file` key mismatch for single-file
worktrees.
- `Match::Search` confirm handler (~line 1640): checks
`wt.read(cx).is_single_file()` and substitutes `RelPath::empty()` for
`path_match.path` to prevent duplication.

- `crates/file_finder/src/file_finder_tests.rs` — Two test changes:
- New test `test_non_project_file_open_with_filter`: opens a file
outside the project, filters for it by name, confirms, and asserts the
correct path is opened.
- Updated `test_search_results_refreshed_on_standalone_file_creation`:
the fix correctly promotes single-file worktree files to
`Match::History`, which activates `skip_focus_for_active_in_search` when
the file is currently open. The test now asserts the match type directly
and closes the picker with `menu::Cancel` instead of confirming.

## Self-Review Checklist

- [x] I've reviewed my own diff for quality, security, and reliability
- [ ] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the UI/UX checklist
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

Release Notes:

- Fixed file picker failing to open non-project files when a filter is
typed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla-signed The user has signed the Contributor License Agreement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

File picker fails to switch to open non-project files when filtered

3 participants