zed/crates/fs
Artem Petryakov 3ea4d186a1
Deduplicate worktree entries from LSP paths with mismatched casing (#61392)
# Objective

On case-insensitive volumes (the macOS default), language servers may
return `Location` URIs whose path casing differs from the worktree's
stored casing - e.g. `Utils/helpers.py` when the on-disk (and worktree)
path is `utils/helpers.py`. `LspStore::open_local_buffer_via_lsp` used
the LSP path verbatim, and worktree selection
(`WorktreeStore::find_worktree`) does a case-sensitive prefix match, so
the existing worktree was either missed (creating a duplicate invisible
worktree) or matched but with a relative path that retained the LSP's
intermediate-component casing. That relative path was then used to
`load_file`, which inserted a brand-new `Entry` keyed by the
differently-cased path alongside the existing one - producing duplicate
file entries in the project panel. This was most visible when navigating
Python imports (Go to Definition) where the LSP returned
differently-cased paths.


https://github.com/user-attachments/assets/e36930b5-8dfd-4b43-8fe4-5317d401e198

## Solution

Canonicalize the LSP-provided absolute path via `fs.canonicalize` before
the worktree lookup in `LspStore::open_local_buffer_via_lsp`, so the
path casing matches the filesystem and the existing worktree/entry is
reused. Canonicalization failures (e.g. a path that doesn't exist on
disk yet) fall back to the original path to preserve prior behavior.

To enable testing this on a fake filesystem, `FakeFs` now supports
`set_case_sensitive(false)` and its `canonicalize` resolves names
case-insensitively, returning the stored (canonical) casing.

## Testing

Added `test_open_buffer_via_lsp_case_variant_no_duplicate` in
`crates/project/tests/integration/lsp_store.rs`. It opens a buffer via
an LSP URI with differently-cased intermediate component
(`/root/SRC/main.rs` vs `/root/src/main.rs`) on a case-insensitive
FakeFs and asserts that no differently-cased entry is created and the
canonical entry is preserved. Verified the test fails without the fix
(`SRC/main.rs` duplicate appears) and passes with it. Existing worktree,
fs, and project_panel test suites remain green.


## Self-Review Checklist:

- [X] I've reviewed my own diff for quality, security, and reliability
- [X] Unsafe blocks (if any) have justifying comments
- [X] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [X] Tests cover the new/changed behavior
- [X] Performance impact has been considered and is acceptable

## Showcase


https://github.com/user-attachments/assets/f052cf10-8b45-4547-8425-00ce4050ee7c

---

Release Notes:

- Fixed duplicate file entries in the project panel on macOS when
navigating to definitions via the language server returned paths with
different casing than the worktree root.

---------

Co-authored-by: Christopher Biscardi <chris@christopherbiscardi.com>
2026-08-20 11:19:14 +00:00
..
src Deduplicate worktree entries from LSP paths with mismatched casing (#61392) 2026-08-20 11:19:14 +00:00
tests/integration fs: Keep trash registry entry when restore fails (#61791) 2026-07-29 10:38:21 +00:00
Cargo.toml Switch from cargo-machete to cargo-shear (#62643) 2026-08-20 10:08:48 +00:00
LICENSE-GPL chore: Change AGPL-licensed crates to GPL (except for collab) (#4231) 2024-01-24 00:26:58 +01:00