7dcda48fdfe21b093a7b2c8039dfca2c28f89708
3365
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
570d9095a7 |
Use Duration to improve type safety and unit correctness (#62969)
# Objective - Prefer using `Duration` instead of integers when dealing with spans of time. This prevents confusing different units of time and comparing arbitrary integers with durations. - Remove `_ms`/`_secs` suffixes from variables which are `Duration`, since their unit is inside of the type. - Initialize large integer constants using `Duration`, which has more descriptive constructors, while maintaining the resulting integer type. Release Notes: - N/A or Added/Fixed/Improved ... |
||
|
|
b4993eb89c |
Properly deduplicate overlapping range formatting results (#62935)
Fixes https://github.com/zed-industries/zed/issues/62780 When formatting changed-only regions, we have received formatting changes that are larger than the regions submitted. Previous code merged only adjacent hunks in a single response, without merging anything else, e.g. multiple responses' ranges that overlapped. Release Notes: - Fixed overlapping range format results duplicating the text |
||
|
|
1829879ca1 |
workspace: Persist recent navigation history across sessions (#55034)
Saves the recent navigation history (up to 20 entries) to the workspace DB so it survives restarts. When reopening a workspace, persisted paths that resolve to the current project are merged into the file finder's history, deduplicated against files already opened in the session. https://github.com/user-attachments/assets/3d8934e1-0da6-4445-8f3d-acc5597d7ac8 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 is consistent with the [UI/UX checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable Closes: https://github.com/zed-industries/zed/issues/56271 Release Notes: - Improved file finder history to include recently opened files from previous sessions. |
||
|
|
629da95e29 |
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> |
||
|
|
255880598d |
Switch from cargo-machete to cargo-shear (#62643)
This results in ~110 crates being removed, and some orphaned files also. --- Release Notes: - N/A Signed-off-by: Neel <neel@zed.dev> |
||
|
|
d5da3168c0 |
search: Fix regex replace with lookahead and lookbehind (#61900)
# Objective - Fixes #25905 - Regex search-and-replace silently does nothing when a same-line pattern contains a lookahead or lookbehind. Searching highlights the correct hits, but Replace All or `:s` in Vim mode leaves the buffer untouched. Reproduce with `316227766016837933199`, search `(\d)(?=(\d{4})+$)` in regex mode, and replace with `$1,`. Expected: `3,1622,7766,0168,3793,3199`. Actual before this change: nothing changes. The same problem affects `(?<=foo: )bar` replaced with `BAZ`. `SearchQuery::replacement_for` expanded the replacement by re-running the whole pattern against the matched text alone. Lookaround assertions inspect text outside the match, so the isolated hit no longer matched and the edit replaced the hit with itself. ## Solution - `replacement_for` now expands from captures located at the exact hit range within its source context. - Single-line regex hits use the complete source line, so lookahead, lookbehind, and line anchors see the same surrounding text used by search. - Literal and escaped-regex searches bypass context reconstruction because their replacements do not use captures. - Multi-line hits retain the exact matched text, preserving the prior cross-line behavior. - If selection boundaries prevent the pattern from matching the reconstructed line, replacement falls back to the isolated hit, preserving prior behavior. - Replace All caches the source line across hits on the same line. Cross-line lookaround remains unchanged: assertions that need text outside a multi-line hit still produce a no-op replacement. Search-within-selection can also retain the prior no-op behavior when the selection boundary changes assertion context. ## Testing - `cargo test -p search test_replace_with_lookaround` (2 passed) - `cargo fmt --all -- --check` - `./script/clippy -p editor -p project -p search` - Tested on Linux arm64. The change is platform independent. ## Self-Review Checklist: - [x] I have reviewed the diff for quality, security, and reliability - [x] Unsafe blocks, if any, have justifying comments - [x] The content adheres to Zed UI standards - [x] Tests cover the changed behavior - [x] Performance impact has been considered and is acceptable --- Release Notes: - Fixed same-line regex replacements that use lookahead or lookbehind |
||
|
|
731096c09a |
Fix project path handling when connecting from Unix to Windows remotes (#62038)
# Objective Follow-up of #61374. Zed now supports Windows as a remote target, but when connecting from a Unix platform to Windows, some path handling still uses the native client's path style (Unix) to construct paths, which causes weird path displays in different areas. One of them is the project path stored in the `settings.json` file, which is related to the open path picker in the codebase: https://github.com/zed-industries/zed/blob/0500fd9ee99a4a98b36e339f3674e391697690fd/crates/open_path_prompt/src/open_path_prompt.rs#L668-L679 For example, if I have a remote project at `D:\code\test_python` and want to open it in remote development, I usually use path completions, with `D:\code\` as the parent path and `test_python` as the selected candidate. Zed directly joins them using `Path::join` on the Unix platform, which results in `D:\code\/test_python`. A second thing I found is the displayed name for the git repo. The related source code is: https://github.com/zed-industries/zed/blob/0500fd9ee99a4a98b36e339f3674e391697690fd/crates/title_bar/src/title_bar.rs#L262-L268 Also taking `D:\code\test_python` as an example: the passed-in `common_dir_abs_path` is `D:\code\test_python\.git`, and `repo_identity_path()` directly uses `Path::file_name()` and `Path::parent()` from the standard library to handle this: https://github.com/zed-industries/zed/blob/0500fd9ee99a4a98b36e339f3674e391697690fd/crates/project/src/git_store.rs#L9956-L9965 Ideally, this function should return `D:\code\test_python`. But due to the platform mismatch, `D:\code\test_python\.git` is returned; after further processing in the title bar, we get `D:\code\test_python\` as the displayed name, while the expected display name is `test_python`. In the past, only Unix-like systems could serve as remote servers, and their path separator (`/`) is valid on Windows, so everything looked fine. But Unix does not support `\` as a valid separator — that's the root cause. We need to use `PathStyle`, which is designed for processing paths across platforms, to deal with these cases. ## Solution - Added new APIs `PathStyle::parent()` and `PathStyle::file_name()`, which serve as replacements for `Path::parent()` and `Path::file_name()` to process paths cross-platform. - Adopted the new APIs in `repo_identity_path()`, and updated the relevant call sites. - For the open path picker, use `PathStyle::join_path()` instead of `Path::join`. ## Testing The added `PathStyle::parent()` and `PathStyle::file_name()` are covered by detailed unit tests. These tests verify that the behavior matches the corresponding methods in `Path`, just independent of the host platform. For the path display issues, I built and tested manually; a comparison is attached in the Showcase section. ## 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) - [ ] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable ## Showcase <details> <summary>Click to view showcase</summary> | Content | Before | After | |:--:|:--:|:--:| |title bar|<img width="486" height="272" alt="title_bar_before" src="https://github.com/user-attachments/assets/d14d0e37-a1b8-43ab-b51b-fe9dd1b977eb" /> | <img width="406" height="274" alt="title_bar_after" src="https://github.com/user-attachments/assets/fc9193f4-d42c-47a8-a254-4ed08c806a11" /> | |path storage| <img width="337" height="264" alt="project_path_before" src="https://github.com/user-attachments/assets/3352add3-20df-43b9-8a20-10ee7d96e703" />| <img width="319" height="262" alt="project_path_after" src="https://github.com/user-attachments/assets/fa3d7feb-f393-416a-868d-85eb0af5cfb8" />| |open remote| <img width="554" height="135" alt="open_remote_before" src="https://github.com/user-attachments/assets/62983eca-22ad-472f-8333-8561cfc17357" />|<img width="562" height="176" alt="open_remote_after" src="https://github.com/user-attachments/assets/22528a6b-0e73-4a12-a825-673ba57a63da" /> | </details> ## Other things to note This PR also did a little refactoring: it moved the `PathStyle`-related tests from the `util` crate to the `path` crate, and updated the documentation to reflect that Windows can serve as a remote platform. The recent project picker also suffers from the same cross-platform bug, but it is not fixed here, because a clean fix requires dealing with database storage, unlike the direct API changes made here. I will address it in a follow-up PR. This PR looks very large, but most of the changes are the test migration and the new API implementation. I hope the unit tests and comments can offload some of the burden for reviewers. --- Release Notes: - Fixed project paths being built incorrectly when connecting from Unix machines to Windows remote servers. |
||
|
|
9fa09ccc24 |
Remove deprecated std::usize import from uniform_list.rs (#62841)
<img width="993" height="370" alt="image" src="https://github.com/user-attachments/assets/15e3a185-3328-4069-ad86-21d29f647f83" /> # Objective - using `std::usize` currently is a warning, but it's a hard fairule in rust nightly - gpui-web requires rust nightly - https://doc.rust-lang.org/std/usize/index.html ## Solution - remove std::usize import, it would be used a primitive type ## Testing - https://github.com/iamnbutler/gpui-unofficial/actions/runs/32189970651/job/95882109895#step:8:753 ## 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 --- Release Notes: - N/A --------- Co-authored-by: Kirill Bulatov <kirill@zed.dev> |
||
|
|
ac9a03c4b9 |
Make opening large files use less peak memory (#62748)
# Objective Opening a file laods it twice. `decode_file_text` builds the whole file as a `String`, and that `String` stays alive alongside the finished rope while `text::Buffer::new` copies it in. The `Vec` behind it grows by doubling, so it also commits up to nearly the file's size again in capacity it never uses. Partially addresses #27283. ## Solution Add `decode_file_text_to_rope`, which streams the file in 1 MB blocks straight into a `Rope`, validating UTF-8 and normalizing line endings as it goes. The file is never fully held as a `String`. `LoadedFile::text` becomes a `Rope` carrying the `LineEnding` detected before normalizing, so `buffer_store` calls `Buffer::new_normalized`. ## Testing On a 729 MB SQL dump, peak memory fell 25% and CPU fell around 28%. tested on 5950x, win11. Release Notes: - Improved memory use when opening large files, reducing peak memory during load by roughly the size of the file itself. |
||
|
|
e30a1d822b |
project: Anchor diagnostic related information that points into the buffer (#62805)
Closes #62796. Follow-up to #62110. # Objective The range of a diagnostic entry is anchored when it is ingested, so it follows edits. The ranges in the related information kept on the diagnostic were the ones the server published. A code action request carried both and reported the same note at two different lines: the entry Zed flattened that note into had followed the edit, the related information had not. The distance does not correct itself either. When diagnostics are merged rather than replaced, the existing entries are re-collected from their anchors while the payload is cloned as it is, so the two positions drift further apart with every edit that passes. `mlir-lsp-server` shows what this costs. `MLIRTextFile::getCodeActions` takes the line number out of `relatedInformation`, and `getCodeActionForDiagnostic` resolves it against its own current document, reading that line to copy its indentation before inserting the `expected-note` check. ## Solution The related information moves from `Diagnostic` onto `DiagnosticEntry<T>`, next to the range it belongs with. The locations of the diagnostic's own file are then in the same coordinate space as that range: anchors inside the buffer, points in the worktree's store. `Diagnostic` carries no coordinates again, so nothing that is only meaningful inside one buffer travels with a payload that outlives it. Every transition goes through `DiagnosticEntry::map_coordinates`: the unsaved-edit adjustment and the clipping when diagnostics are ingested, the anchoring in `DiagnosticSet::new`, and the conversion back to points in `merge_diagnostic_entries`. Only the diagnostic's own range is widened when it is empty, since that is for how it is rendered, while the related locations are reported back as the server framed them. Locations in another file have nothing here to anchor to and are kept as published, which is also what `mlir-lsp-server` expects, since it skips them. `DiagnosticEntryRef` is left alone. It is what the rendering path iterates, down to the scrollbar markers that walk every diagnostic of the buffer on each frame, so nothing there converts or allocates. The entries are read through `diagnostic_entries_in_range` where the request is built, and `diagnostics_in_range` is now implemented on top of it. The field is an `Option`, as an empty `Arc<[_]>` still allocates and most diagnostics carry no related information. `data` has the same staleness and cannot be anchored, as it is opaque. ## Commits The third commit is mechanical: it introduces `DiagnosticEntry::new` and rewrites the literals at its call sites, so that the last commit holds only the change of behaviour. ## Testing Three tests, all failing before this change. The first two are added as separate commits, so that they can be run against `main`: - `test_code_actions_related_information_follows_edits` edits above the note and requests code actions, where the two positions for it used to disagree. - `test_code_actions_related_information_drifts_across_merges` edits and pulls diagnostics twice, where the distance used to be every line inserted since the diagnostic was published rather than the last edit alone. - `test_code_actions_related_information_of_disk_based_diagnostics` publishes a diagnostic computed against the file on disk while the buffer holds an unsaved edit, covering the adjustment the two positions share. - `cargo test -p project` - `cargo test -p language -p diagnostics -p editor` - `cargo fmt --all -- --check` - `./script/clippy -p project -p language` ## 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 --- Release Notes: - Fixed language servers receiving outdated positions for the related information of a diagnostic when code actions are requested. |
||
|
|
12f3994269 |
git_ui: Dismiss askpass prompts when requests end (#61292)
# Objective Fixes #47623 - When authenticating git commands using a security key through `askpass`. The modal which asks for user presence does not get dismissed even after the git command finishes successfully. ## Solution Add a cancellation task to the `AskPassModal`, which gets dropped when the requested operation completes. This cancellation task then dismisses the modal. ## Testing - I've tried authentication through `askpass` using my own security key. Testing both successful and failed authentication. - I've added tests which confirm that the modal gets dismissed when a task is cancelled, and that the cancellation is triggered when `ask_password` Task gets dropped. Willing to pair on review, message me on Slack. Showcase video left out because it would leak private information. ## 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 Release Notes: - Fixed authentication prompts not dismissing automatically when using security keys with ssh |
||
|
|
ef973c67c0 |
Add support for the "..." entry in file_scan_exclusions (#62769)
## Objective `file_scan_exclusions` replaces the defaults instead of adding to them, so excluding one extra directory means restating all eleven default globs and never picking up defaults added in later Zed releases. ## Solution `file_scan_exclusions` now accepts the `"..."` entry, which expands to the value it overrides, so `["**/node_modules", "..."]` adds to the inherited globs instead of replacing them. Entries listed by name keep their position, and leaving `"..."` out still replaces the list outright, so existing settings behave exactly as they do today. ## Testing - Four unit tests in `crates/settings_content/src/project.rs` cover splicing versus replacing, accumulation across successive layers, and edge cases: a repeated `"..."`, an empty list clearing the value, and a bare `["..."]` leaving it unchanged. - To check by hand: set `"file_scan_exclusions": ["**/node_modules", "..."]` in user settings and confirm `node_modules` disappears from the project panel and file finder while `.git` and `.DS_Store` stay excluded. Remove `"..."` and confirm only `node_modules` is excluded. Repeat in a project's `.zed/settings.json` to confirm it splices the resolved user settings rather than the defaults. - Tested on macOS. This is platform-independent settings-merge logic with no OS-specific code paths, so I did not test Linux or Windows. ## 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 --- Release Notes: - Added support for the `"..."` entry in `file_scan_exclusions`. Custom exclusions can now extend the defaults instead of replacing them. |
||
|
|
f652da59e8 |
Added Tracked , Staged options to stash (#62254)
# Objective Closes #62252 The Git Panel could only stash *everything* — `Stash All` runs `git stash push --include-untracked`, sweeping tracked edits and untracked files into a single entry. There was no way to stash a subset, so the common workflows of "park my tracked edits but keep my new scratch files" and "park what I've staged and keep working on the rest" required dropping to the terminal. ## Images <img width="389" height="358" alt="Screenshot 2026-08-10 at 3 10 50 PM" src="https://github.com/user-attachments/assets/18e4c943-e320-4802-ada8-59e54bf4cefd" /> <img width="504" height="462" alt="Screenshot 2026-08-10 at 3 10 37 PM" src="https://github.com/user-attachments/assets/783237eb-980d-47bc-a0f5-17b03a23a60c" /> ## Solution Add two stash variants alongside `Stash All`, surfaced in the Git Panel's overflow menu based on how the list is currently grouped, so the menu mirrors the sections the user can actually see: | Group By | Stash entries offered | | --- | --- | | None | Stash All | | Tracked & Untracked | Stash All, **Stash Tracked** | | Staged & Unstaged | Stash All, **Stash Staged** | - **`git::StashTracked`** stashes tracked changes and leaves untracked files in place. It reuses the existing pathspec plumbing (`Repository::stash_entries`), filtering the status list down to the paths to stash. - **`git::StashStaged`** stashes the index only, leaving unstaged changes in place. This *cannot* be expressed as a pathspec — a partially staged file would have its unstaged hunks stashed too — so it needs git's own `--staged` flag. That meant a new `GitRepository::stash_staged` backend method and an `optional bool staged` field on `proto::Stash` so remote projects work too. Both actions are unbound by default and are dispatchable from the command palette when the panel is focused. One subtlety worth calling out for review: `Stash Tracked` filters on `FileStatus::is_created()`, not `is_untracked()`. Staging a new file flips it from `Untracked` to `Tracked { Added }`, but the panel still lists it under **Untracked** — using `is_untracked()` meant staged-new files were silently stashed. `is_created()` is the same predicate the panel uses to build that section (`git_panel.rs`), so the menu item and the list can no longer disagree. This branch also includes a separate commit adding **per-section staging** (`git::StageSection` / `git::UnstageSection`) — right-click a file to stage or unstage every entry in its section. Happy to split that into its own PR if preferred. ## Testing Manually tested on macOS against a scratch repo with a mix of states: modified tracked files, untracked files, and untracked files that had been staged. - `Stash Tracked` with tracked edits + untracked files → only tracked edits stashed; untracked files remain. - `Stash Tracked` with untracked files **staged** → they remain, staged. This was broken in an earlier revision and drove the `is_created()` fix above. - `Stash Staged` with one file staged and another modified-but-unstaged → only the staged file is stashed; the unstaged edit and untracked files survive. - `Stash Pop` round-trips both cases back to the original state, with no conflicts. - Menu contents and disabled states verified in all three Group By modes. - Per-section staging covered by a new unit test, `test_stage_section_scopes_to_selected_section`. Not covered by automated tests: the stash actions themselves. `FakeGitRepository` leaves every stash method `unimplemented!()`, so stash behavior isn't reachable from GPUI tests today — consistent with the existing untested `StashAll`. Adding fake-repo stash support looks like a worthwhile follow-up but felt out of scope here. Reviewers on non-macOS platforms: nothing here is platform-specific. Note that `Stash Staged` requires **git 2.35+** (Jan 2022) for `git stash push --staged`; older git surfaces a clear error toast rather than failing opaquely. The remote path (`proto::Stash.staged`) has not been exercised against a live collab session. ## 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 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 Release Notes: - Added `Stash Tracked` and `Stash Staged` options to the Git Panel, letting you stash only tracked changes or only staged changes. --------- Co-authored-by: Christopher Biscardi <chris@christopherbiscardi.com> |
||
|
|
c51e4fb1b4 |
project: Deduplicate identical language server hover responses (#62266)
Closes https://github.com/zed-industries/zed/issues/62262 ## Solution Identical hover responses from multiple language servers should be displayed only once. Different hover responses should still all be preserved, since multiple language servers may provide complementary information. ## Showcase https://github.com/user-attachments/assets/67246d9f-ed1c-4f5a-98f5-f10548b7fc6d --- Release Notes: - Deduplicated identical language server hover responses --------- Signed-off-by: Xiaobo Liu <cppcoffee@gmail.com> Co-authored-by: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com> |
||
|
|
3c0fad36ea |
project: Send diagnostic related information in code action requests (#62110)
Closes #62560. Supersedes #62108, which was a subset of this one. Overlaps #62400, see comments. # Objective Zed flattens the `relatedInformation` of a diagnostic into non-primary entries of the same diagnostic group. Before this change it did not retain the original related information on the primary diagnostic, so code action requests were built from the entries intersecting the requested range, with the primary diagnostic carrying no `relatedInformation`. This caused incomplete code actions from servers such as `mlir-lsp-server`, which generates `expected-note` edits by walking the related information of an error or warning diagnostic. ## Solution Keep the related information the server published on the primary diagnostic when the diagnostic comes in, next to `data`, and pass it back when building the code action request. Nothing is removed from `context.diagnostics`: the flattened entries are still sent as before, so a diagnostic the server published on its own and that Zed merged into a group as supporting information keeps being sent with the severity the server gave it. What it does not recover is that diagnostic's own `relatedInformation`: ingestion keeps only its severity. Unchanged from `main`. Reassembling it from the flattened entries instead, which is what the first revision of this PR did, is neither faithful — ingestion trims messages and drops entries with an empty message or pointing at another file — nor cheap: diagnostics are not indexed by group, so every request would scan all diagnostics of the buffer, once per server, on every selection change. One caveat: the stored ranges are the ones the server published rather than anchors, so they do not follow edits made after the diagnostic arrived, while the primary's range does. An edit in that window can put a resolved insertion a few lines off — `mlir-lsp-server` places the `expected-note` line at the note's own position. `data` has the same property today. Anchoring them would mean carrying related information through the anchor conversion, which I would rather do as a follow-up if you consider it worth it. The field is not carried over the proto conversion, as LSP requests are only built by the peer that received the diagnostics from the language server. ## Testing New tests for: - related information sent verbatim, including the cross-file and empty entries that flattening drops; - no related information; - a flattened entry whose primary is outside the requested range; - a server-published supporting diagnostic; - two servers on the same buffer. Verified on the repro from #62560 that `mlir-lsp-server` inserts both the `expected-error` and the `expected-note` check ([screenshot](https://github.com/zed-industries/zed/issues/62560#issuecomment-5278476460)). - `cargo test -p project` - `cargo test -p language -p editor -p diagnostics` - `cargo fmt --all -- --check` - `./script/clippy -p project -p language` ## 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 --- Release Notes: - Fixed incomplete code actions from language servers that rely on the related information of a diagnostic. |
||
|
|
75c80abb31 |
git: Decode non-UTF-8 blobs for project diffs (#60821)
## Summary Fixes #56449. Related to #16965. Zed’s Git panel and Project Diff build UI diffs from `language::Buffer` diff bases loaded through the Git backend. Git blob loading previously converted bytes with `String::from_utf8(...).ok()`, so legacy-encoded blobs were treated as missing and the whole worktree file appeared newly added. This follows the same encoding path used for worktree buffers: - move shared byte decoding and encoding into `language` - keep Git blob, revision, and index APIs byte-oriented with `Vec<u8>` - decode diff bases and index contents in `GitStore`, where `language::Buffer`s are created - encode index writes using the open buffer’s encoding and BOM so partial staging does not rewrite the file as UTF-8 - keep worktree loading and saving on the same shared implementation Regression coverage includes Windows-1251 decoding/encoding, UTF-8/UTF-16 BOM preservation, raw Windows-1251 Git blob loading, and a `BufferDiffSnapshot` assertion that a one-line CP1251 edit produces one modified-line hunk instead of a full-file rewrite. This does not run Git `textconv` commands. It fixes the reported legacy-encoding case without executing repository-configured commands or modifying working files on disk. ## Testing - `cargo test -p language file_content::tests --locked` - `cargo test -p git repository::tests::test_load_revisions --locked` - `CARGO_INCREMENTAL=0 cargo test -p project git_store::tests::test_decode_git_text_windows_1251_one_line_change --locked` - `CARGO_INCREMENTAL=0 cargo test -p project --test integration test_restaging_hunk_after_optimistic_unstage --locked` - `CARGO_INCREMENTAL=0 cargo check -p project --tests --locked` - `CARGO_INCREMENTAL=0 cargo check -p git_ui --tests --locked` - `cargo fmt --all --check` - `git diff --check` ## Suggested .rules additions - N/A Release Notes: - Fixed Git panel and Project Diff rendering for legacy-encoded text files whose Git blobs are not valid UTF-8. --------- Co-authored-by: Cole Miller <cole@zed.dev> |
||
|
|
468837a78d |
Merge array settings from extension contributions instead of overwriting (#62686)
Closes https://github.com/zed-industries/zed/issues/62572 Reworks https://github.com/zed-industries/zed/pull/54950 — instead of unconditionally replacing the array with a different one, now does the replacement only when the user settings are set. The rest now merges into the array. Release Notes: - Fixed array merging for extensions case |
||
|
|
abacaae1cd |
Make search much faster (#62658)
# Objective Project search sends one candidate per file to its worker pool, and each one carried an owned `Snapshot`. Every field of `Snapshot` is cheap to clone except `always_included_entries`, a `Vec<Arc<RelPath>>` holding one entry per always-included file. With a broad file_scan_inclusions such as **/*, that vector holds an entry per file in the project, so cloning it once per file made search O(files²). Partially addresses #38799 (still needs to fix the huge memory usage and the occasional stutters) . ## Solution Share the snapshot behind an `Arc` instead, the consumer only reads `id()`, `abs_path()` and `root_name()`, so nothing needs an owned copy. ## Testing Using the [linux kernel repo](https://github.com/torvalds/linux), i searched for `vmx_l1d_should_flush ` and `netif_rx` and its at least 60x faster on 5950x. with `file_scan_inclusions: ["**/*"]` Release Notes: - Fixed project search being very slow on projects that set a broad `file_scan_inclusions` |
||
|
|
c1dab7a0d3 |
Support blaming parent revisions (#62614)
Closes https://github.com/zed-industries/zed/discussions/42583 Adds more tooltip entries and `editor::BlameRevision`, `editor::BlamePreviousRevision` actions to use. Started to highlight gutter blame entries that belong to currently annotated commit. https://github.com/user-attachments/assets/ba754e0b-6431-407c-8d79-2f8b0324fde1 Release Notes: - Supported blaming parent revisions |
||
|
|
851bf3d499 |
Make file scanner less eager in non-git-tracked directory trees (#62583)
Fixes https://github.com/zed-industries/zed/issues/35780 Collab schema migration PR: https://github.com/zed-industries/cloud/pull/3422 The corresponding database schema migration has been created in the Cloud repo and applied to the production database. Before, Zed scanned each and every entry in the tree down from the directory it was opened in, except gitignored files and scan exclusions. The approach is unchanged, if Zed detects it was open inside a git repository: e.g. the directory open in Zed contains `.git` directory. For the rest of the projects, 2 optimizations are made: * Limit the depth of file scan traversal. Now, `file_scan_depth` (default `5`) restricts Zed from traversing any directory that has same number or more segments in its file path. Such directories behave similar to gitignored directories: their contents is not available in file finder, project search and project panel, but can be lazily traversed when the directory is expanded (e.g. project panel expands it or a nested file is open by path via terminal, etc.) To indicate that to the users, a status entry is shown firs time the limitation is hit in the project: <img width="858" height="133" alt="image" src="https://github.com/user-attachments/assets/7da6cfbb-98b4-4cc3-bf2a-8902a9597a15" /> * During the scan, any git repositories that are not direct children of the directory open in Zed (depth >= 2), are traversed and indexed normally, but their git metadata is never fetched eagerly. Only when Zed opens a buffer from that repo the git metadata is fetched and applied. All that combined now uses a way more moderate amount of CPU and RAM when opening `~`: <img width="1717" height="368" alt="Screenshot 2026-08-13 at 17 43 53" src="https://github.com/user-attachments/assets/ec83e2a9-f7cc-452b-8eb7-af158284ca4e" /> File scan inclusions and exclusions are considered still for such projects. Set `file_scan_depth` to `0` to enable old behavior. The setting is supported in the project settings, so custom values can be set based on the project's structure. --- Release Notes: - Fixed Zed using a lot of memory and CPU in large, non-git-tracked, directory trees |
||
|
|
fc58ad2226 |
Unify non-Unicode file detection code (#62581)
Closes https://github.com/zed-industries/zed/issues/62464 Closes https://github.com/zed-industries/zed/issues/62212 As a bonus, fixes the project search not working in BOM'd UTF-16 files. Release Notes: - Fixed project search not working in some non-Unicode files |
||
|
|
ed4e541a6c |
Send correct line endings to language servers (#59941)
# Objective Zed normalizes all buffer text to `LF` internally, but was sending that `LF`-normalized text to language servers even for `CRLF` files. This caused servers such as ESLint (with a `linebreak-style` rule) to report a false error on every line. Fixes #38453 ## Solution Send the buffer's actual line endings to the language server instead: - `didOpen` and full-document `didChange` now send `text_with_line_endings()`, and incremental changes apply the buffer's line ending to each edit. - Normalize the line endings returning from the LSP before computing changed regions - This effectively incorporates the fix from #59151, which happens to be the reason this change was [originally reverted](https://github.com/zed-industries/zed/commit/b595846ba7cf15b9c0f6130b1d5130a6f28f52d0). As such, that PR should likely be integrated first. - Detect when a buffer's line ending differs from what a server was last sent and force a full-document resync, without this the server would keep stale line endings, as the incremental change tracking does not consider line ending differences. - Route the `UpdateLineEnding` operation to `on_buffer_edited` so toggling line endings via the status bar notifies the server immediately rather than waiting for the file to be edited or reopened. ## Testing - Did you test these changes? If so, how? Yes, in addition to new unit test coverage, I used a test project with ESLint configured with the `linebreak-style` rule set to enforce CRLF line endings to verify that the LSP integration worked as expected. - Are there any parts that need more testing? The original reversion seems to have been due to a regression in which LSP formatting would cause the editor to scroll to the bottom. I'm not seeing this in my reproduction, and I believe this was due to a failure to normalize line endings coming back from the LSP, but I don't know the exact circumstances that led to the original reversion, so there might be some additional things to test there. - How can other people (reviewers) test your changes? Is there anything specific they need to know? Not really! As mentioned above, configuring ESLint with the `linebreak-style` rule is probably the easiest way to test. - If relevant, what platforms did you test these changes on, and are there any important ones you can't test? I tested on Linux, but I don't believe it's relevant. ## 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/881c5758-a5de-433c-8fd6-3cad7478aa90 --- Release Notes: - Fixed an issue where language servers received incorrect line endings for `CRLF` files, causing linters and formatters to report false errors. --------- Co-authored-by: Kirill Bulatov <kirill@zed.dev> |
||
|
|
3e19851f8f |
editor: Keep the cursor before text inserted by on-type formatting (#61823)
## Why `textDocument/onTypeFormatting` edits that insert or replace text at an empty cursor use its right bias and move it past the new text. In paired tags, pressing Enter can therefore leave the cursor on the closing tag instead of between the tags. ## What - Capture a left-biased pin for each empty cursor before requesting on-type formatting. - Skip cursor tracking unless a matching language server advertises the trigger. - Restore only unchanged empty cursors whose displacement is fully covered by formatting transaction ranges, so intervening user edits are preserved. - Reset vertical movement state when restoring a cursor. ## Testing - `cargo test -p editor test_on_type_formatting` (5 passed) - `./script/clippy -p editor` ## References - Fixes https://github.com/zed-industries/zed/issues/61574 Release Notes: - Fixed the cursor being moved past text inserted or replaced at its position during on-type formatting. --------- Co-authored-by: Kirill Bulatov <kirill@zed.dev> |
||
|
|
22a5bab822 |
Respect the filterText of LSP completion items during completion filtering (#62433)
# Objective Closes #61646. For code completions, Zed currently fuzzy-matches against `CodeLabel::filter_text()`: https://github.com/zed-industries/zed/blob/ddd9b3a3f09fe67258b81e017414df37266809d0/crates/editor/src/code_context_menus.rs#L337-L343 `CodeLabel::filter_text()` is a substring of `CodeLabel.text`, which is essentially the text itself. `CodeLabel.text` is constructed by Zed's per-language adapters from the `label` and `detail` fields of the completion items returned by the language server — the exact construction differs from adapter to adapter, but the source data is the same. In effect, `CodeLabel.text` ≈ `label` + `detail`. Zed therefore filters on the server-returned `label` and `detail`, while the server-returned `filterText` field is silently ignored.Per the LSP spec: ``` /** * A string that should be used when filtering a set of * completion items. When omitted, the label is used as the * filter text for this item. */ filterText?: string; ``` we should use `filterText` when it is provided. Normally, language servers populate `filterText` as a substring of `label`, so the current behavior works fine. But for certain language servers or functions, `filterText` can be entirely unrelated to `label` and `detail`. For example, for `std::path::Path::parent()` in Rust, rust-analyzer returns: ```json { "label": "parent()", "labelDetails": { "detail": "(alias dirname)", "description": "fn(&self) -> Option<&Path>" }, "kind": 2, "preselect": true, "sortText": "7ffffff6", "filterText": "parentdirname", ... } ``` Typing `dirname` therefore never surfaces this completion. The root design issue behind this bug is that `CodeLabel` is not well-suited to filtering LSP completions. ## Solution `CodeLabel` and its related methods are kept untouched: the struct is reused across the repo and is only unsuitable for filtering LSP completions. Instead, the changes are made in `CompletionSource` and `Completion`, each gaining a `filter_text()` method: - `CompletionSource::filter_text()` handles LSP completions, returning the server-provided `filterText` and falling back to the `label` when `filterText` is absent. - `Completion::filter_text()` is the general entry point used for fuzzy matching; for non-LSP completions it falls back to the existing `label.filter_text()`. The fuzzy match target is switched from `CodeLabel::filter_text()` to `Completion::filter_text()` — that is the core change. Since the fuzzy match target is no longer guaranteed to be a substring of the displayed `CodeLabel.text`, the matched characters no longer have a direct position in the displayed text to highlight. Bold highlights are therefore only rendered when `CodeLabel::filter_text()` equals `Completion::filter_text()`. This is a safe choice, though not an ideal one. ## Testing Added a new GPUI test covering the new behavior; also built and tested with a before/after comparison, attached in the Showcase section. ## 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 | Before | After | |:--:|:--:| | <img width="708" height="308" alt="Before" src="https://github.com/user-attachments/assets/ca2e3820-7ea1-4dcc-a91f-28aab71aecc5" /> | <img width="696" height="248" alt="After" src="https://github.com/user-attachments/assets/334e240b-64d5-495b-aef6-772456b993ba" /> | --- Release Notes: - Improved completion filtering for lsp completions. |
||
|
|
fa19fe3c5c |
project: Don't let a canceled caller leak a loading worktree forever (#61009)
# Objective `WorktreeStore::find_or_create_worktree` inserts the shared worktree-creation task into `loading_worktrees` and relies on the task it returns to each caller to remove that entry once creation resolves. But the creation task keeps running through the clone the map itself holds, while the map cleanup lives only in the callers' returned tasks. If every caller is cancelled before creation resolves, the resolved task stays in `loading_worktrees` forever, retaining the `Entity<Worktree>` captured in its result (a `Shared` task memoizes its output). Such a worktree can never be released: `remove_worktree` only unlists it, so its background scan keeps running and its snapshot keeps growing for the lifetime of the window. The stale entry also keeps `initial_scan_complete` permanently `false` (that flag is `loading_worktrees.is_empty() && …`). Callers are cancelled routinely — worktree creation is async and can take seconds on a large tree, while the tasks awaiting it are owned by UI that the user can close at any time (a tab or pane, a debugger panel resolving a path, an agent session, or the whole window). See the existing note in `crates/zed/src/zed.rs` that external-file worktrees are "released on file close". Observed in the wild: a home-directory worktree removed from the project kept scanning for hours and grew Zed past 45 GB; neither removing the folder nor ending the agent session freed it — only quitting Zed. (The scan-amplification half of that incident is #60988.) ## Solution Spawn the map cleanup as its own detached task, next to the map insertion, so a loading entry always leaves `loading_worktrees` when loading resolves regardless of what happens to the callers. The returned per-caller task is unchanged apart from no longer owning that cleanup. ## Testing - Added `test_worktree_released_when_creation_caller_is_cancelled`: it requests a worktree, drops the returned task immediately (as a cancelled caller would), lets creation complete, removes the worktree, and asserts the entity is released. It fails on `main` and passes with this change. - Full worktree-related project integration suite is green (45/45). ## 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 Release Notes: - Fixed a memory leak where a worktree whose creation was requested by a since-cancelled task (e.g. a folder opened as its owning tab/panel/window closed) could never be released, leaving its background scan running and its snapshot growing for the lifetime of the window. --------- Co-authored-by: Kirill Bulatov <kirill@zed.dev> |
||
|
|
da4d4832a1 |
project: Keep the buffer associated after an LSP rename also renames the file (#61142)
# Objective `test_rename_that_also_renames_file` (added in #59104) is order-dependent: it passes at seed 0, which CI runs, but fails on many others (e.g. 11, 15, 17). Any unrelated change that schedules one extra task shifts the deterministic test scheduler enough to flip it at seed 0 too — which is how it surfaced, while working on #61009. The bug it exposes is real and pre-existing: #59104 stopped the content swap, but the open buffer still relied on the filesystem watcher to follow the file to its new path. Depending on the order the watcher reports the old path's deletion and the new path's creation, the entry id isn't carried over, and the buffer is stranded at the now-deleted old path (shown as saved) and never re-associates. ## Solution Move the worktree entry explicitly after the rename, preserving its id, the same way `rename_entry` (project panel renames) already does. ## Testing - `test_rename_that_also_renames_file` now runs 30 seeds to cover both orderings. ## 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 Release Notes: - Fixed a symbol rename that also renames the file leaving the open buffer on the old path |
||
|
|
2d43977f08 |
markdown_preview: Fix images not rendering over remote (#62490)
Closes #39860 This PR resolves relative image paths from the Markdown source file's project path and load images through the project image store. SVG images over remote connections remain unsupported and are left for a follow-up. Release Notes: - Fixed images not rendering in Markdown Preview over remote. |
||
|
|
e90e6d2407 |
project: Fix SymbolKind serialization over RPC (#62458)
# Objective I noticed that in workspace symbol search, the function's symbol kind has become `Trait`. ## Solution Add `to_proto` and a macro to define the mapping instead of `as i32`. ## Testing Updated the test. ## 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 --- Release Notes: - Fixed `SymbolKind` mapping to LSP protocol values |
||
|
|
1d8ba864ae |
Add optional message support to git stash (#62439)
Show a modal when invoking the stash action to allow users to provide an optional custom message for the stash entry. Closes #62430 # Image <img width="1622" height="1106" alt="Screenshot 2026-08-10 at 9 14 00 PM" src="https://github.com/user-attachments/assets/0d26dac2-919d-4bb1-b6a7-433ceff18955" /> <img width="1622" height="1106" alt="Screenshot 2026-08-10 at 9 14 11 PM" src="https://github.com/user-attachments/assets/896b68ff-999f-4ec9-a6a4-e0e7a6867286" /> # Objective Zed's stash action runs `git stash push --quiet --include-untracked --` with no `-m`, so every stash is labelled with git's auto-generated `WIP on <branch>: <sha> <subject>`. That text describes the commit you were sitting on, not what you stashed — so two stashes taken from the same commit are indistinguishable. This undercuts the stash picker (`git::ViewStash`), which lists entries as `#<index>: <message>` and fuzzy-searches over exactly that string. The search box already exists; there is just nothing meaningful to search, because every candidate is a variation of the same auto-generated line. ## Solution `git::StashAll` now opens a single-line modal ("Optionally provide a stash message") before stashing. - Confirming with text passes `--message <text>` to `git stash push`. - Confirming with the field empty omits the flag entirely, keeping git's default description — so the prompt is a one-keystroke pass-through and existing muscle memory still works. - Cancelling aborts the stash, so the prompt doubles as a confirmation step. Implementation: - `StashMessageModal` (`Editor::single_line`) in `git_panel.rs`, toggled from `GitPanel::stash_all`. `menu::Confirm` trims the input and maps empty to `None`. - `message: Option<String>` threaded through `Repository::stash_all` → `stash_entries` → `GitRepository::stash_paths`. The flag is appended before the `--` separator so a message is never parsed as a pathspec. - New `message` field on the `Stash` proto message, so remote and collab projects behave identically. One non-obvious detail: the modal is opened via `cx.defer_in` rather than inline. `git::StashAll` is registered on the workspace (`git_ui.rs`) as well as on the panel element, and `Workspace::register_action` dispatches while `Workspace` is leased — so opening the modal inline re-enters that update and hits GPUI's `double_lease_panic`. This only reproduces when focus is *outside* the Git Panel, which makes it easy to miss. `Option<String>` rather than `String` is deliberate: `--message ""` produces a blank stash description, which is strictly worse than git's default. ## Testing Manually verified the modal in a local build on macOS: the prompt appears on `git::StashAll`, accepts a message, and the named entry shows up in the stash picker. Also verified at the git level by replaying the exact argument vector `stash_paths` builds against a scratch repo with mixed staged / unstaged / untracked changes: | Case | Result | |---|---| | `stash push --quiet --include-untracked --message "my named stash" -- <paths>` | `stash@{0}: my named stash`; worktree clean, untracked file included | | same, without `--message` | `stash@{0}: <sha> <subject>` — git's default text | | `--message "x" --` with no paths (clean repo) | exit 0, no stash created — the empty pathspec does **not** stash everything | `cargo fmt --check` clean, `./script/clippy -p git -p fs -p project -p git_ui` passes with `--deny warnings`, and the existing suites pass (`cargo test -p project -p git_ui`, 436 tests). Worth a reviewer's attention: trigger `git::StashAll` with focus in the **editor** rather than the Git Panel. That routes through the workspace action registration and is the case the `cx.defer_in` deferral exists to keep from panicking. No new automated tests — the behavior is testable with the existing `git_panel.rs` harness (`init_test`, `GitPanel::new`) if reviewers would prefer coverage over a manual check. ## Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments — n/a, no unsafe added - [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) - [ ] Tests cover the new/changed behavior — no new tests; see Testing - [x] Performance impact has been considered and is acceptable — one extra process argument; no new work on any hot path --- Release Notes: - Added an optional stash message prompt when stashing changes ` --------- Co-authored-by: Chris Biscardi <chris@christopherbiscardi.com> |
||
|
|
4043c82956 |
git_panel: Add copy path actions to the context menu (#62352)
# Objective When developing remotely, when I close the uncommitted changes tab, I need some time to load before I can copy the path. Or have to switch to the project panel to find the specific file. All of this is annoying, so I added a copy path action to the git panel's context menu and key bindings consistent with the project panel. ## Solution Already described in the Objective section. ## Testing I wrote a unit test and tested it manually. ## 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 <img width="411" height="535" alt="showcase" src="https://github.com/user-attachments/assets/a17e7633-eb92-4737-aa30-958fe58bb99f" /> <img width="717" height="427" alt="showcase" src="https://github.com/user-attachments/assets/d067e892-17de-4527-ac20-16cad6f38015" /> --- Release Notes: - Added "Copy Path" and "Copy Relative Path" actions to the Git Panel's context menu |
||
|
|
7d6722f9f4 |
Show error toast on startup for malformed tasks (#62387)
Closes https://github.com/zed-industries/zed/issues/61208 Before, Zed showed no toasts on startup when tasks.json contained malformed entries, also if there were two top-level arrays, the last one was silently discarded without any toasts too. The PR fixes both. Release Notes: - Fixed error toast not showing for malformed tasks.json |
||
|
|
3692029a80 |
Bump rustc to 1.97 (#62395)
Release Notes: - N/A |
||
|
|
2a19ae92ea |
lsp: Separate timed RPC log groups (#61452)
RPC log grouping only tracked whether consecutive messages had the same
transport direction. This made an untimed request appear beneath the
duration header of an unrelated response when both were sent in the same
direction.
Before:
// Send (took 53.0ms):
{"jsonrpc":"2.0","id":"##CodeLensRefreshRequest#1226","result":null}
{"jsonrpc":"2.0","id":53,"method":"textDocument/diagnostic"}
After:
// Send (took 53.0ms):
{"jsonrpc":"2.0","id":"##CodeLensRefreshRequest#1226","result":null}
// Send:
{"jsonrpc":"2.0","id":53,"method":"textDocument/diagnostic"}
Apply the same boundary handling to received messages while continuing
to group consecutive untimed messages.
---
Release Notes:
- N/A or Added/Fixed/Improved ...
|
||
|
|
5278e17de7 |
project: Compare WorktreePaths by pairing, not by path sets (#62144)
# Objective - Prevent changed main/folder associations from being skipped during thread metadata updates. ## Solution - Compare WorktreePaths as ordered main/folder pairs. - Keep PathList equality order-insensitive. ## Testing - cargo test -p project test_worktree_paths_equality_compares_pairings ## Self-Review Checklist: - [x] I have reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content adheres to Zed UI standards - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable --- Release Notes: - N/A |
||
|
|
874e91241e |
Respect regex assertions more faithfully with search (#62158)
- **project_search: Add failing test for regex searches with assertions** - **project_search: Improve handling of regex assertions** # Objective Fixes #55995 by removing a faulty optimization path for regex searches. ## Solution ## Testing We've added 3 extra tests for the changed behavior. ## 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 > This section is optional. If this PR does not include a visual change or does not add a new user-facing feature, you can delete this section. - Help others understand the result of this PR by showcasing your awesome work! - If this PR includes a visual change, consider adding a screenshot, GIF, or video - A before/after comparison is very useful for changes to existing features! While a showcase should aim to be brief and digestible, you can use a toggleable section to save space on longer showcases: <details> <summary>Click to view showcase</summary> My super cool demos here </details> --- Release Notes: - Improved handling of regexes in project/buffer searches --------- Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com> |
||
|
|
25a090b15d |
project: Refresh MCP settings after worktree changes (#62026)
# Objective Prevent MCP servers from remaining unavailable when a project is created before its first worktree. ## Solution Refresh effective MCP settings before maintaining servers after worktree additions or removals. ## 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 --- Release Notes: - Agent: Fixed MCP servers missing from new project threads after a worktree opens. |
||
|
|
42875d0c1d |
project: Fix branch diff with older servers (#62134)
# Objective Prevent branch diffs from failing when a server does not recognize worktree diff requests. ## Solution Send `HEAD` as a valid committed-only fallback for servers that ignore `includes_worktree`. ## 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) - [ ] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable --- Release Notes: - N/A |
||
|
|
0500fd9ee9 |
git: Add diff_base setting for showing changes since the default branch (#61501)
# Objective Let git indicators — the editor gutter, file colors, and `git::Diff` — show all changes on the current branch relative to its merge base with the default branch, instead of only uncommitted changes. Supersedes #60398; thanks to @samuelcolvin for the original implementation and motivation. Closes FR-135 ## Solution - New `git.diff_base` setting (`"head"` | `"default_branch"`), applied live and toggleable per session from the editor controls menu ("Diff Against Default Branch"). - Statuses come from a real merge-base-to-worktree tree diff (`git diff --merge-base`), so local edits that revert branch changes correctly show as unchanged. - `GitStore` shares one `DiffBufferList` per repository with the Branch Diff view; `repo_snapshots` and `project_path_git_status` keep returning index/worktree truth, while display surfaces use separate `display_*` APIs. - `BufferDiff` now records what its base is (`DiffBaseKind`); hunks whose base isn't HEAD are read-only in the gutter — stage/restore buttons and keybindings are inert, so committed work can't be silently rewritten. - `git::Diff` follows the setting; new `git::DiffHead` always opens the HEAD diff; `git::BranchDiff` is renamed `git::DiffBranch` (deprecated alias kept). Tradeoffs / known limitations: - Hunk-level staging is unavailable while in `default_branch` mode (whole-file staging via the git panel still works). Staging just the uncommitted sub-ranges of a branch hunk is a follow-up. - Remote hosts running an older server ignore the new `GetTreeDiff.includes_worktree` proto field and degrade to committed-changes-only branch diffs. - Repositories with no resolvable default branch fall back to HEAD-relative behavior; a failed first resolution retries on the next branch-list change. ## Testing - Real-git-repo tests for the merge-base-to-worktree diff's edge cases: files recreated after index deletion, committed deletions recreated on disk, and symlinks. - GPUI tests for status semantics (a branch change reverted on disk shows clean), `git::Diff` routing, live setting changes, and read-only hunk enforcement (restore/stage leave buffer and index untouched). ## 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 --- Release Notes: - Git: Added a `git.diff_base` setting (`"head"` or `"default_branch"`) that makes the editor gutter, file colors, and diff view show all changes on the current branch since its merge base with the default branch, instead of only uncommitted changes. --------- Co-authored-by: Ben Kunkle <ben@zed.dev> |
||
|
|
9fb397d961 |
workspace: Fix dropping Windows files onto a WSL remote (#57146)
Dropping a local Windows file (e.g. `E:\foo\bar.md`) onto a Zed window connected to a WSL remote previously forwarded the path verbatim. On the remote Linux side `E:\foo\bar.md` isn't absolute, so it got joined with the worktree CWD, producing nonsense like `/home/user/E:\foo\bar.md` and a "failed to canonicalize root path" error from the worktree scanner. 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 is consistent with the [UI/UX checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable Closes #49915 before: <img width="1343" height="331" alt="before" src="https://github.com/user-attachments/assets/193cfbf6-d07e-4c5f-b941-75e4a0c62345" /> after: <img width="1181" height="288" alt="after" src="https://github.com/user-attachments/assets/7ad56e13-3723-4b48-aa3d-59eca6038a7f" /> Release Notes: - Fixed dragging local Windows files onto a Zed window connected to a WSL remote. |
||
|
|
d8c3ed1acb |
Register Git submodules under their own project path (#61859)
Closes #61671 A submodule's `.git` is a file pointing into the superproject's `.git/modules/<name>`, which looks just like a linked worktree's `.git` file. The identity-path resolution used for recent projects and project grouping treated them the same, so submodules got registered under `.git/modules/<name>` instead of their own folder. The fix detects submodule git dirs (`is_submodule_git_dir`) and skips resolution for them, so a submodule keeps its own working directory as its identity. Linked worktrees and bare repos are unaffected. ### Current vs. Expected Current: opening submodule `Foo/Bar` registers the path as `Foo/.git/modules/Bar`. Expected: it registers as `Foo/Bar`, like any other project. ### Video https://github.com/user-attachments/assets/e2eee5e7-ef64-47ed-9780-6fcafda5ae30 ### Tests - `is_submodule_git_dir` unit test - `resolve_git_worktree_to_main_repo` returns `None` for a submodule - persistence test asserting the submodule identity stays at its own folder Release Notes: - Fixed Git submodules being registered under the parent repository's `.git/modules` directory instead of their own path |
||
|
|
5d4a11358d |
Do not drop other servers' data on semantic token refresh (#61795)
Closes https://github.com/zed-industries/zed/issues/60825 Release Notes: - Fixed semantic tokens overly invalidated on `workspace/semanticTokens/refresh` |
||
|
|
a153cbfbaf |
Stop the npm cache from growing without bound (#61750)
# Objective - Fixes #59409. Closes FR-143. Zed's managed npm directory reaches 10–17GB on machines that use external agents, and is never pruned. - Two independent causes: registry agents are launched with `npm exec`, which keys its install directory on the requested version, so every agent release leaves a full ~250MB copy behind; and npm never evicts anything from its download cache. ## Solution - Install registry agents into a directory we reuse, so npm replaces the previous version in place instead of accumulating one copy per release. As a side effect, updates now download only the changed dependencies rather than the whole tree. - Empty the download cache on startup. Nothing in it needs to survive a restart, since packages are installed elsewhere. It has to go wholesale: deleting individual downloads leaves npm's index pointing at missing files, and npm then fails with `ENOENT` rather than fetching them again. - The first launch after this does one full agent install as it moves into its new home, and reclaims whatever the old directories were holding. ## Testing - Installed the real agent at 0.33.1, then upgraded to 0.42.0 in the same directory: 253MB → 256MB, against two separate copies today. The resolved executable answers an ACP `initialize`. - macOS only. Windows deserves a look — it should be better than before, since the agent is now launched as a plain `.js` file with Node instead of through npm's `.cmd` shim, but I can't verify it. ## 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) - [ ] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable --- Release Notes: - Fixed the bundled npm cache growing without bound, which could consume many gigabytes of disk. |
||
|
|
b9e8d99a71 |
git: Do not re-compute git_access for .git/ changes (#60503)
This builds on #59521 and addresses @dinocosta's comment https://github.com/zed-industries/zed/pull/59521#pullrequestreview-4563460240 Looking at it again, I think https://github.com/zed-industries/zed/pull/59521/commits/e7ed02cc4963868632ba97a1fb09f1b398d3b22b was too conservative. Re-running the access check on every commit, stage, or checkout, doesn't really make sense. Access depends on `.git` ownership/permissions and on the global `safe.directory` config. File writes in `.git/` can actually never change the access. The only case where this access can change is an external command that changes the ownership or permission of the folder. That sounds like a quite rare edge case and I'm not 100% sure whether all file watchers even currently correctly trigger events for ownership changes. @dinocosta Let me know what you think. Release Notes: - Improved Git Panel performance by avoiding redundant repository access checks. Co-authored-by: dino <dinojoaocosta@gmail.com> |
||
|
|
a59eeb8436 |
Instantly acknowledge workspace/diagnostic/refresh (#61772)
Closes https://github.com/zed-industries/zed/issues/61692 Makes no sense to wait for anything at all when receiving such requests, https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#diagnostic_refresh does not imply anything either. Release Notes: - Fixed diagnostics refresh deadlocking certain language servers |
||
|
|
90483395af |
project: Fix panic when an inlay hint response outlives its buffer version (#61747)
# Objective Fix a nightly crash where Zed aborts on a bounds-check panic in the inlay hint cache. `LspStore::inlay_hints` captures a `RowChunk` before awaiting the language server, then reads the hint cache with that chunk's id afterwards. If the buffer shrank meanwhile, `latest_lsp_data` has already rebuilt the cache with fewer chunks, so the stale id indexes out of bounds. Chunks are 50 rows, so the reported crash only needed a ~150-250 line deletion, not a drastic edit. Regressed in #61523. Nightly only; the regressing commit is in no release tag, so this never reached preview or stable. Fixes ZED-AGY Fixes FR-142 ## Solution - Return an empty result when the buffer version no longer matches, so a stale chunk id can never index the rebuilt cache. The stale *writes* were already guarded by this version check; only the read sat outside it. - An empty result is already treated as "not fetched", so the chunk is simply re-requested on the next refresh. ## Testing `test_inlay_hint_response_after_buffer_shrinks` reproduces the abort deterministically and passes with the fix. Note that it drives the race through a fake language server rather than a real one. ## 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 --- Release Notes: - N/A |
||
|
|
0cc6d59389 |
Properly replace hints per each chunk (#61562)
Follow-up to hints part of https://github.com/zed-industries/zed/pull/61523 Instead of appending to the chunk data, we have to replace as we always get all hints for the entire chunk. Given that we order and invalidate the requests by `Version`, this can only happen when a racy requests from e.g. same file split or /refresh and edit etc. happens. Release Notes: - N/A |
||
|
|
281f6a5e02 |
Refresh git state on bare .git events (#59876)
# Objective Fix stale Git state in Zed when repository metadata changes are reported only as a bare `.git` directory event. On macOS, file watcher events can be coalesced such that Git operations only surface as a `Changed` event for the `.git` directory itself, rather than individual events for files like `.git/index` or `.git/HEAD`. Zed previously ignored bare `.git` directory events before scheduling a Git metadata refresh, which could leave the Git panel showing stale changes or an outdated history even though `git status` / `git log` reflected the latest state. ## Solution Treat meaningful bare `.git` directory events as Git repository updates before skipping them from normal worktree scanning. This preserves the existing behavior of not scanning `.git` as regular project content, while still notifying the Git repository tracking path that repository metadata may have changed. As a result, Git state such as `HEAD` and file statuses are refreshed when `.git` itself is the only watcher event. Updated the existing worktree test expectations so bare `.git` events now trigger `UpdatedGitRepositories`, while skipped files like `.git/index.lock` still do not. Added a test covering the full project/Git path: - repo initially has old `HEAD` and a modified file status - fake Git state is updated to represent a commit - only a bare `.git Changed` event is emitted - Zed refreshes the repository snapshot, observes the new `HEAD`, and clears the stale file status ## Testing The new tests cover the full project/Git path scenario described above. It fails without the fix and passes with the fix. Unfortunately, i was unable to reproduce the issue deterministically enough to test it end to end. ## 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 --- Release Notes: - Fixed stale Git panel state after repository metadata changes. Co-authored-by: Eric Holk <eric@zed.dev> |
||
|
|
1db5b3ae06 |
project: Prevent empty external formatter output from clearing buffers (#61276)
## Context Zed runs external formatters as stdin/stdout filters: it writes the current buffer to stdin and replaces the buffer with the formatter's stdout. Commands such as `cargo fmt` instead rewrite files on disk and exit successfully without producing stdout, causing Zed to interpret the empty output as the formatted contents and clear a non-empty buffer. The fix treats empty stdout from a successful external formatter as no output when the original buffer is non-empty. Zed leaves the buffer unchanged and displays a notification explaining that the formatter did not return formatted contents. The formatter documentation now clarifies the stdin/stdout contract and recommends using the Rust language server or invoking `rustfmt` directly. Closes #56344 Behavior before the fix : [Screencast from 2026-07-19 02-58-29.webm](https://github.com/user-attachments/assets/61fc5bf9-4420-43f1-94a3-394bbbc4f2a0) Behavior after the fix : [Screencast from 2026-07-19 02-55-35.webm](https://github.com/user-attachments/assets/21062065-6b95-4cd4-8200-506f5681d98e) ## How to Review **crates/project/src/lsp_store.rs** Start with `format_via_external_command`, which now checks whether a successful formatter returned empty stdout while the input buffer was non-empty. In that case, it returns `None` before constructing a diff, preventing the buffer contents from being replaced with an empty string. Then review the external formatter branch in `apply_formatter`: when it receives `None`, it skips extending the formatting transaction, logs the condition, and emits an `LspStoreEvent::Notification` explaining why the buffer was left unchanged. **crates/editor/src/editor_tests.rs** Adds a GPUI regression test that configures an external command to consume stdin and return no stdout. It uses platform-specific commands for Windows and Unix, invokes manual formatting on a non-empty Rust buffer, and verifies that the buffer remains unchanged, the operation is not recorded as a formatter failure, and a notification is emitted. **docs/src/reference/all-settings.md** Extends the external formatter documentation to state that formatters must return the formatted buffer through stdout. It calls out file-rewriting tools such as `cargo fmt` as incompatible and recommends using the Rust language server or `rustfmt --emit stdout`. ## 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 external formatters that produce no output clearing non-empty buffers |
||
|
|
737f3384f0 |
git_ui: Add option to commit with --no-verify (#61529)
Follow-up to #61185, which moved hook execution from Zed into `git commit` itself. There was previously no way to skip hooks from the UI; #59846 and #56318 attempted to add one on top of the old behavior. This PR adds support on top of the new implementation. Adds a “Skip Hooks” toggle to the commit menus in the Git panel and commit modal, with a corresponding command-palette action. When enabled, the next commit runs with `git commit --no-verify`, skipping pre-commit and commit-msg hooks. The toggle clears after a successful commit or when switching repositories, but remains enabled when a commit fails so it can be retried. Release Notes: - Added a “Skip Hooks” commit option that skips pre-commit and commit-msg hooks. |
||
|
|
aa1fd6bff0 |
Calculate buffer chunks lazily (#61523)
<img width="1728" height="1084" alt="image" src="https://github.com/user-attachments/assets/a560b10a-6e26-43ff-b830-c528e2dc6798" /> Before, each edit in a 50 MB plaintext file would trigger a lot of anchor calculations (as chunk is 50 lines only) done on main thread + did extra work when no language grammar or brackets were available. The PR now moves all anchor calculations into `computed_chunks: Mutex<HashMap<usize, RowChunk>>,` cache miss. `TreeSitterData` is wrapped in `Arc` and shared as a part of the snapshot, hence the need for `Mutex` and internal mutability here. Trace after the changes: <img width="1728" height="1084" alt="image" src="https://github.com/user-attachments/assets/cb258980-8461-4559-b725-aef63c835e60" /> Release Notes: - Improved input performance in large files --------- Co-authored-by: Finn Evers <finn@zed.dev> |