ac94de78ab696fc897b82de467490c1a57e72a6d
94
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
b6490c5fbd |
Stop re-resolving editorconfig sections on every language settings lookup (#63323)
Closes https://github.com/zed-industries/zed/issues/59689
Symbolicating the reporter's profile (21s of typing, Windows) showed
`Window::draw` taking 63% of the main thread at ~62 redraws/s (p95 draw
= 40ms), and 30.9% of the *entire* main thread inside
`EditorconfigStore::properties()`:
every `LanguageSettings` lookup — several per frame via
`DisplayMap::tab_size`, `MultiBuffer::language_settings`, indent guides,
and `LspStore::supports_range_formatting` — re-ran the full editorconfig
resolution (ancestor walk plus `ec4rs::Section::apply_to` over every key
of every section) and then cloned the whole `LanguageSettings` struct.
Real-world `.editorconfig` files carry hundreds of irrelevant keys
(`dotnet_*`, `ij_*`, ...), so the per-call map assembly dominated:
`RtlAllocateHeap` 7.3%, `memcmp` 7.0%, `memcpy` 6.6%,
`Properties::find_idx` 5.9% self time.
## Commit 1: resolve only the editorconfig properties Zed reads
- `EditorconfigStore::properties()` now applies only the 7 keys Zed
consumes (`indent_style`, `indent_size`, `tab_width`, `end_of_line`,
`max_line_length`, `insert_final_newline`, `trim_trailing_whitespace`)
instead of materializing every key of every matching section.
- Worktrees with no editorconfig at all now return `None` early instead
of allocating an empty `Properties` and forcing a `LanguageSettings`
clone on every lookup.
- Adds an `editor_render_with_editorconfig` benchmark: maximized window,
file-backed buffer at `src/app/components/editor_pane.ts`, a root
`.editorconfig` shaped after [the second
report](https://github.com/zed-industries/zed/issues/59689#issuecomment-5475124891)
(no `root = true`, a `[*]` section with ~3200 keys, 25 sections with
large `{...}` alternation lists) plus a 4-level nested chain, and a
typing workload (insert/delete + cursor moves).
```
main (
|
||
|
|
2e1cd0fbb2 |
project: Underline diagnostics reported past the end of a line (#63125)
Closes #22473. Some language servers report a syntax error whose range starts at the end of one line and ends at the start of the next — e.g. Pyright/ruff/ty/pyrefly on a Python function missing its trailing `:`: ``` range: { start: { line: 0, character: 11 }, end: { line: 1, character: 0 } } ``` That range spans nothing but the line terminator, so there's no glyph left for the editor to underline. The diagnostic is real (it shows up in the status bar and the diagnostics panel) but never gets a visible squiggle in the buffer, which makes it very easy to miss — especially since a missing `:` is one of the most common Python typos. ## Fix `update_buffer_diagnostics` already collapses *empty* ranges onto an adjacent character. This adds a sibling case for ranges that are exactly `line_start..next_line_start` (i.e. cover only the terminator): they're pulled back onto the last character of the line they actually concern, the same way empty ranges are. Ranges are only touched when the end position is precisely the start of the next line, so genuinely multi-line diagnostics that happen to *start* at an end-of-line position are left untouched. ## Testing Added `test_diagnostic_range_spanning_line_terminator` in `project_tests.rs`, modeled on the neighboring `test_empty_diagnostic_ranges`, asserting the closing `)` of `def main()` gets the error highlight instead of the range being invisible. Verified against real language servers: reproduced the exact same `start..next_line_start` range on ruff 0.16.4, ty 0.0.74, and pyrefly 1.2.0 for a missing `:`, matching the LSP trace pyright produced in #22473. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Release Notes: - Fixed diagnostics not being underlined when their range covers only a line terminator (e.g. a missing `:` in Python) --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: Kirill Bulatov <kirill@zed.dev> Co-authored-by: Kirill Bulatov <mail4score@gmail.com> |
||
|
|
09440c85cb |
lsp: Add client support for LSP 3.18 markdown diagnostic messages (#61030)
LSP 3.18 allows servers to send [`MarkupContent` diagnostic messages](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#diagnostic), guarded by the client capability `textDocument.diagnostic.markupMessageSupport`. - Advertise `markup_message_support` only while pull diagnostics are enabled because `textDocument.diagnostic` is the pull-model capability. LSP 3.18 currently has no equivalent capability for push diagnostics: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#diagnosticClientCapabilities https://github.com/microsoft/language-server-protocol/issues/2246 - Handle `string | MarkupContent` messages in both push and pull diagnostic paths: markdown-kind messages populate the existing `Diagnostic::markdown` field (rendered in hover popovers and the diagnostics panel), plaintext-kind markup remains plain text, and plain string messages keep going through the adapter's `diagnostic_message_to_markdown`. - Preserve server-provided markup for code actions sent back to the originating server, avoid forwarding markup diagnostics to other servers, and render diagnostic metadata without altering the server-provided markdown. - Carry the markup kind over RPC via a new optional `LspDiagnostic.markup_message_kind` proto field so remote/collab projects round-trip `MarkupContent` messages. Depends on the lsp-types change that turns `Diagnostic.message` into a `DiagnosticMessage` enum (`string | MarkupContent`): https://github.com/zed-industries/lsp-types/pull/15 Once merged, Cargo.toml can point to the upstream commit. Note that Zed already rendered some plain-string diagnostics as Markdown through language-specific adapter hooks, including `rust-analyzer`. This adds protocol-level support for diagnostics explicitly sent as LSP 3.18 `MarkupContent`, while preserving the existing adapter fallbacks. As a result, this does not introduce a new diagnostics rendering pipeline. Server-provided Markdown is routed through the existing `Diagnostic::markdown` path, with small fixes to handle Markdown-only updates and block content correctly. ## Showcase Example from [JETLS.jl](github.com/aviatesk/JETLS.jl) (a Julia language server): > Before <img width="924" height="160" alt="Screenshot 2026-07-15 at 16 05 40" src="https://github.com/user-attachments/assets/b19fe9e3-50e3-44e4-9b4d-ac8bd438d3d6" /> > After <img width="924" height="160" alt="Screenshot 2026-07-15 at 14 13 05" src="https://github.com/user-attachments/assets/359c3382-118d-4fa6-aa91-6bd3661d3d28" /> --- Release Notes: - Added support for rendering LSP 3.18 Markdown diagnostic messages from language servers. --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Kirill Bulatov <mail4score@gmail.com> |
||
|
|
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. |
||
|
|
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. |
||
|
|
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> |
||
|
|
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> |
||
|
|
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 |
||
|
|
3692029a80 |
Bump rustc to 1.97 (#62395)
Release Notes: - N/A |
||
|
|
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 |
||
|
|
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> |
||
|
|
25632b979b |
language: Refactor available_languages into its own struct (#61388)
This adds a dedicated `AvailableLanguages` struct in preparation for a more cabable language matching based on a given language config. No functional changes, just shuffling some code around for this round. Also made the LanguageMatcher non-cloneable in favor of wrapping it in an Arc, since cloning is rather expensive for this and having a reference is sufficient in all cases right now. Release Notes: - N/A --------- Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com> |
||
|
|
3181085ba2 |
Fix cursor going to the end of file when LSP formatter uses CRLF line endings (#59151)
I got super annoyed when using Zed with F#, so I fixed it. This also fixes other LSPs on Windows Fix is super simple, the test fails if the fix is commented out Closes #48367 (and probably others) Release Notes: - fix cursor jumping to the end of file when LSP formats the file using CLRF line endings |
||
|
|
756e764b90 |
project: Track inlay hint / code lens / document symbol registrations by ID (#55340)
extends the precedent set by #43703 (thanks @reflectronic) so that `textDocument/inlayHint`, `textDocument/codeLens`, and `textDocument/documentSymbol` correctly track multiple dynamic registrations by id. previously each register call overwrote the slot on `ServerCapabilities`, and unregister either silently did nothing (inlayHint, documentSymbol — no match arm) or wiped the entire capability (codeLens). now each method keeps its own id-keyed map on `DynamicRegistrations`; the field on `ServerCapabilities` is cleared only when the last registration is removed. textDocument-sync notifications (`didChange`/`didSave`/`willSave`) are deliberately out of scope — their fan-out semantics are ambiguous in the spec and were flagged on @smitbarmase's earlier exploration in #36876. verified with `cargo check -p project -p lsp -p editor`, `cargo test -p project --test integration -- multi_registration` (3/3 passing), and `cargo fmt -p project`. closes part of #37838. Release Notes: - Improved support for language servers that dynamically register inlay hints, code lens, or document symbols multiple times. --------- Co-authored-by: Kirill Bulatov <kirill@zed.dev> |
||
|
|
cb68afbd2b |
Respect disabled trailing whitespace removal (#58776)
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 #58686 Release Notes: - Fixed `.editorconfig` re-enabling trailing whitespace removal when Zed settings disable it. --------- Co-authored-by: Martin Ye <martin@zed.dev> |
||
|
|
df5d437085 |
Disable LSP for files with very long lines (#61447)
Release Notes: - Fixed ui stutters when opening large single line files like minified javascript due to running LSP requests against them |
||
|
|
2328aebf25 |
git_panel: Show staged and unstaged diff stats (#60815)
# Objective - Show accurate diff stats for each staged and unstaged projection of a partially staged file in the Git panel. - This was originally considered for https://github.com/zed-industries/zed/pull/59884, but was scoped out of that already-large PR and is being submitted separately as discussed there. ## Solution - Collect HEAD-to-index and index-to-worktree diff stats alongside the existing combined HEAD-to-worktree stats. - Carry the staged and unstaged stats through repository status snapshots and remote status serialization. - Use the stat matching the projected Git panel section while preserving the combined stat for the other grouping modes. - Update the fake Git repository and add regression coverage with deliberately different staged and unstaged counts. ## Testing - `cargo check -p git_ui` - `cargo check -p collab` - `cargo test -p git_ui test_group_by_staging_section_membership_and_order --lib` - `cargo test -p project --lib --no-run` - `cargo fmt --all -- --check` - `git diff --check` ## 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 diff stats for partially staged files in the Git panel |
||
|
|
728cb247e9 |
buffer_diff: Canonicalize ambiguous hunk placement to fix staging corruption (#60584)
Closes #60424 ## Problem With the repro from #60424, staging the first deletion hunk marked the second deletion as staged in the UI even though git still had it unstaged, and clicking the (incorrectly shown) Unstage button inserted a duplicate copy of the hunk's contents into the git index on every click. The root cause is ambiguous hunk placement. The committed text contains repeated `end\n\n` line runs, so the deletion hunks can "slide": more than one placement produces a minimal diff. The uncommitted diff (HEAD vs worktree) anchored the remaining deletion at one row while the unstaged diff (index vs worktree), recomputed after the partial stage, anchored the same logical deletion at a different row. Everything that correlates hunks across those two diffs assumes they agree on positions: - the secondary-status matching in `hunks_intersecting_range_impl` found no unstaged hunk at the uncommitted hunk's rows and reported it as staged (`NoSecondaryHunk`); - the worktree→index projection in `compute_uncommitted_index_edits` treated the hunk's position as unchanged text and, on unstage, inserted the hunk's HEAD content at an index position that already contained it, duplicating it on every request. ## Fix Upgrade `imara-diff` from 0.1.8 to 0.2.0 and run `Diff::postprocess_lines` (imara-diff's port of git's xdiff slider/indent heuristic) after computing hunks in `buffer_diff`. This canonicalizes the placement of ambiguous hunks based only on their local content, so diffs of the same buffer against different base texts anchor the same logical change at the same rows. A bonus is that Zed's hunk placement now matches `git diff`'s output for such cases (git has used the indent heuristic by default since 2.11). As defense in depth, `compute_uncommitted_index_edits` now drops a pure-insertion index edit whose content is already present at the target position, so a stale secondary status can no longer duplicate index content. The imara-diff 0.2 API removed the `Sink` trait and the top-level `diff()` function, so the other call sites (`language/text_diff.rs`, `zeta_prompt/udiff.rs`, `edit_prediction_metrics/reversal.rs`) are migrated mechanically to `Diff::compute` + `hunks()` with unchanged behavior (0.2 also renamed `lines_with_terminator` to `lines` and changed the default `&str` tokenization to include terminators; the unified-diff builders keep terminator-less tokens via `str::lines()`). ## Testing - New regression test `test_staging_hunks_with_ambiguous_placement` replays the exact repro from #60424 (same file contents): stages the first deletion, asserts the remaining hunks keep their unstaged status and the index matches exactly, then issues repeated unstage requests for the unstaged hunk and asserts the index is unchanged. Before the fix this test showed the second hunk flipping to staged and the index growing by one copy of the deleted block per unstage request. - `buffer_diff`, `language`, `zeta_prompt`, `edit_prediction_metrics`, `multi_buffer`, `git_ui`, `editor`, and the `project` integration suite pass. - One test expectation updated: `editor::test_fold_function_bodies` asserted the old placement of an ambiguous deletion (blank line before comment); the canonicalized placement (comment before blank line) matches what `git diff` produces for the same texts. Release Notes: - Fixed staging a hunk sometimes marking a different hunk as staged (and subsequent unstaging corrupting the git index) when the diff contained repeated lines ([#60424](https://github.com/zed-industries/zed/issues/60424)). --------- Co-authored-by: Cole Miller <cole@zed.dev> |
||
|
|
330ec055b3 |
project: Fix agent hanging indefinitely when pulling workspace diagnostics (#61176)
The agent's diagnostics tool waits on pull_workspace_diagnostics_once, which enqueues a completion signal into the background workspace diagnostics refresh loop. When a language server failed to answer workspace/diagnostic requests, that signal could be stranded, leaving the agent stuck on 'Check project diagnostics' (reported with logs full of 'Timeout during workspace diagnostics pull' and requests cancelled after 120s). Three hang paths in lsp_workspace_diagnostics_refresh: 1. Timeouts never resolved the completion signal. On ConnectionResult::Timeout the loop just retried, holding the waiter through up to 50 attempts x 120s each (~100 minutes) before the sender was finally dropped. 2. Waiters could queue behind an already-hanging request. The refresh channel has capacity 1; if the loop was mid-retry (e.g. the initial pull at server startup was timing out), a newly enqueued waiter sat unreceived until the entire retry cycle ended. 3. The request timeout was permanently disabled after the first partial result. The timer raced progress_rx.recv() once and became pending() forever if progress won, so a server that streamed one chunk and then stalled hung the request indefinitely. Fixes: - On timeout, release all pending waiters (including ones that queued mid-flight) with refreshed = false, so callers fall back to cached diagnostics after at most one timeout period while the background loop keeps retrying. - Carry waiters as a Vec and absorb refresh requests queued during backoff/in-flight requests into the current attempt instead of serializing them behind it. - Restart the timeout whenever a partial result arrives, turning it into an inactivity timeout: streaming servers get unlimited total time while they keep making progress, but a stalled stream now times out instead of hanging forever. Adds a regression test with a fake server that never answers workspace diagnostic pulls, verifying the waiter resolves after the timeout; it fails with 'Parking forbidden' (infinite hang) without the fix. Closes FR-124 Release Notes: - Fixed agents hanging indefinitely if an LSP server never responds to diagnostics requests |
||
|
|
272d4f1cc2 |
project: Persist workspace diagnostics when closing buffer (#59875)
# Objective Closes #50739 Many language servers have settings for their diagnostic mode, typically supporting either "single file" mode or "workspace" mode. In single file mode, the language server only generates diagnostics for files that the user has open. When a file is closed, those diagnostics are cleared. This is the behavior currently implemented in Zed. However, when a language server runs in workspace mode, we should retain all diagnostics regardless of whether the corresponding file is open or closed. As reported in #50739, Zed currently discards these diagnostics when a buffer is closed, just like in single file mode. When a buffer is completely closed, Zed triggers a diagnostics update to perform cleanup: https://github.com/zed-industries/zed/blob/6e8b0ae150b6140a398a87a3eb1cd4dd1568c504/crates/project/src/lsp_store.rs#L4747-L4773 and the Pulled diagnostics are all cleaned, that's why when closing a buffer, the diagnostic summary disappeared. This process aggressively clears all `Pulled` diagnostics, causing the diagnostic summary for the closed file to disappear. ## Solution Filter the target language servers when updating diagnostics on buffer close. If a language server has workspace diagnostics enabled, we skip clearing its diagnostics. ## Testing Added two new integration tests in `crates/project/tests/integration/project_tests.rs`: 1. `test_diagnostic_summaries_cleared_on_buffer_close_without_workspace_diagnostics`: Verifies that diagnostics are cleared on buffer close when workspace diagnostics is disabled. 2. `test_diagnostic_summaries_retained_on_buffer_close_with_workspace_diagnostics`: Verifies that diagnostics are retained when workspace diagnostics are enabled. (This test fails on the current `main` branch). I have also verified this functionality locally. Both local and remote development environments work as expected. ## 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 <details> <summary>Click to view showcase</summary> My super cool demos here </details> --- Release Notes: - Fixed workspace diagnostics being cleared when closing a buffer. |
||
|
|
6b6393fb0b |
Split out RelPath into a separate crate (#61029)
This is necessary to remove some `util` dependencies from crates, as well as better sharing for our projects. This also includes the WIP AbsPath abstraction as well as some bug fixes from internal tooling. Release Notes: - N/A or Added/Fixed/Improved ... |
||
|
|
b4018f4c7e |
Open gitignored subdirectories as their own workspace (#60918)
# Objective Let's git ignored directories be opened as their own project ## Solution - Add an "ignored dir" carve out when checking project collision ## Testing - Added tests ## Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [-] Unsafe blocks (if any) have justifying comments - [-] 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 - [-] Performance impact has been considered and is acceptable --- Release Notes: - |
||
|
|
fb4885a55e |
Open non-writeable files in Capability::Read mode (#57202)
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 #57174 Release Notes: - Open non-writeable files in Capability::Read mode Co-authored-by: Lukas Wirth <lukas@zed.dev> |
||
|
|
c09d59120c |
project: Fix content swap when an LSP rename also renames the file (#59104)
A "rename symbol" whose workspace edit also renames the file (a `TextDocumentEdit` followed by a `RenameFile` resource operation) only applied the text edit to the in-memory buffer. The on-disk file still held the pre-edit content, so the blind `fs.rename` moved stale bytes to the new path while the edited buffer was stranded at the old path, swapping the two files' contents. This persists a dirty buffer for the rename source before renaming, so the new file receives the edited content and the now-clean buffer can't be saved back to the old path. 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 - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable Closes #59077 Release Notes: - Fixed a symbol rename that also renames the file swapping the contents of the old and new files |
||
|
|
48192372a0 |
Git partially staged changes (#46541)
This PR explores the addition of a new feature and UI to improve visibility into partially staged commits. Currently, the Git panel shows tracked and untracked changes, but it does not clearly distinguish between staged and unstaged changes. As a result, it’s difficult to quickly see which changes are not staged in the current UI. Both staged and unstaged changes are combined into the `Uncommitted Changes` multibuffer. This developer experience differs from other editors, most notably VS Code; which presents separate Staged Changes and Changes lists. ### Staged and unstaged diffs in multibuffers This PR introduces an alternative UI for unstaged changes that aligns with the overall Zed experience. Instead of showing changes on a per-file basis, staged and unstaged diffs are each displayed in their own multibuffers, similar to how `Uncommitted Changes` currently works. For example the following screenshot shows the current `Uncommitted Changes` on the left, the `Staged Changes` in the middle and the `Unstaged Changes` buffer on the right for comparison <img width="1408" height="859" src="https://github.com/user-attachments/assets/aa709f7a-041d-4cb1-95d6-84c0f5fff688" /> ### Indicators/interactions The new multibuffers can be opened in two ways: 1. Via a new `U` chip, which appears when a file has unstaged changes 2. Via new menu options (See screenshots below for both interaction paths.) <table> <tr> <td style="text-align: center; vertical-align: top;"> <p>via the chip</p> <img height="400" src="https://github.com/user-attachments/assets/3ef69f02-b787-499c-959a-25f50b3728e8" alt="Via the chip" /> </td> <td style="text-align: center; vertical-align: top;"> <p>via the menu</p> <img height="400" src="https://github.com/user-attachments/assets/f5be8b6d-ccdc-4420-bd29-75570b558016" alt="Via the menu" /> </td> </tr> </table> ### Design goals - minimally intrusive UI changes (small new badge and menu items) - adhere by Zed'ism (use multibuffer where possible) - avoid disabling any current interactions (Uncommitted Changes ui is unchanged) - avoid introducing an app level view mode (no new settings needed) ### Experience goals - make it easy to see what changes are not staged - make it easy to see that a file has unstaged changes (avoid developers accidently leaving out changes in a commit; a personal issue that I have when using Zed) - elegantly handle large file's unstaged changes (follows the same collapse and expanding seen in `Uncommitted Changes`) ### How to try - Clone the repo and run `cargo run` - Make a change to a file and stage it - Make another change to the file (the `U` indicator will appear) - Click the `U` to see the unstaged view ### Open questions/rough edges - [ ] determine if this user experience is useful for others - [ ] ensure all interactions work as expected (response to all update cases) In general I'm really interested in hearing the community's feedback about this interface, more than happy to make any changes or explore a different solution! ### Related issue: - https://github.com/zed-industries/zed/pull/36646 - https://github.com/zed-industries/zed/issues/26560 Release Notes: - Support partially staged commit multibuffers via a staged and unstaged changes view. --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Cole Miller <cole@zed.dev> |
||
|
|
f023a7e4a3 |
Fix worktree grouping for bare checkouts (#59968)
Summary - Track whether a worktree root is itself a linked Git worktree. - Use that metadata when computing project group keys so bare checkout worktrees group under the repository identity path. - Propagate the metadata through remote worktree protocols and add local/remote regression coverage. Background Bare checkout layouts can place linked worktrees under the repository identity directory, e.g. `/monty/.bare` with worktrees like `/monty/feature-a`. We were treating those linked worktree paths as separate project identities, which caused the sidebar to move agent threads under the active worktree instead of the shared repository group. We also exclude adding this to collab intentionally, we can open a different PR for that if we need to. Closes #59910 Closes AI-431 Test Plan - `cargo fmt --package project --package worktree --package remote_server --package workspace --package collab --package proto` - `git --no-pager diff --check` - `cargo test -p project test_project_group_key -- --nocapture` - `cargo test -p remote_server test_remote_root_repo_common_dir -- --nocapture` - `cargo test -p worktree remote_worktree -- --nocapture` - `cargo test -p workspace test_remote_project_root_dir_changes_update_groups -- --nocapture` - `cargo check -p collab` 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](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) Tests cover the new/changed behavior Performance impact has been considered and is acceptable Release Notes: - Fixed agent thread/sidebar grouping for Git worktrees backed by bare checkouts. --------- Co-authored-by: Anthony Eid <anthony@zed.dev> |
||
|
|
7a00c48ddc |
git_panel: Fix stale Git status entries for moved directories (#59934)
# Objective Fix stale Git status entries for moved directories ## Solution Coalesce changed paths before scanning and remove cached descendant statuses when a directory disappears from the current status set. ## 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 status entries for moved directories |
||
|
|
314cfdccfb |
Allow empty values in .editorconfig (#60026)
Closes https://github.com/zed-industries/zed/pull/59559 Closes https://github.com/zed-industries/zed/issues/59466 Release Notes: - Fixed incorrect parsing of .editorconfig with empty values |
||
|
|
c43971d69c |
Handle dynamic registration of semantic tokens capability (#60015)
In C# files nothing gets semantic highlighting — class fields and other identifiers are colored by tree-sitter only, so a private field looks the same as a plain local variable. The reason: Roslyn (the C# language server) doesn't declare `semanticTokensProvider` statically in its `initialize` response. It registers it **dynamically** (`client/registerCapability`), and only when the client advertises `textDocument.semanticTokens.dynamicRegistration = true`. Zed advertised `false` and didn't handle such a registration, so Roslyn never offered semantic tokens at all. (rust-analyzer/gopls are unaffected — they declare the capability statically.) This is the first of two PRs. This one makes Roslyn actually **send** semantic tokens. The companion PR (#60027) maps Roslyn's C#-specific token types to theme styles — without it the tokens arrive but most are dropped, since their types aren't in Zed's default rules. ## Solution - Advertise `textDocument.semanticTokens.dynamicRegistration = true`. - Handle the `textDocument/semanticTokens` registration and unregistration so the capability is stored, following the existing arms for `documentLink`, diagnostics, etc. ## Testing - Added a test that dynamically registers and unregisters `textDocument/semanticTokens` and checks the stored capability appears and is cleared. - Verified manually against Roslyn on a C# project: Zed now sends `textDocument/semanticTokens/full` and gets tokens back; before this change there was no semantic-token traffic at all. ## Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable --- Release Notes: - Support dynamic registration of the `textDocument/semanticTokens` capability. --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
5bdcb12042 |
Fix project grouping for Git repo subdirectories (#57998)
Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - No unsafe blocks added. - [x] The content is consistent with the [UI/UX checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) - No new UI components; behavior better matches user intent for opened folders. - [x] Tests cover the new/changed behavior - Added sibling-subdirectory project group regression coverage. - Extended subfolder Git-status test to ensure Git still uses the parent repo while project identity stays at the opened folder. - [x] Performance impact has been considered and is acceptable - Change adds one small enum/optional field check when computing worktree paths; no meaningful performance impact expected. Closes #57997 Release Notes: - Fixed project grouping for opened subdirectories that share the same parent Git repository. ## Screenshots ### Before <img width="334" height="224" alt="Screenshot 2026-05-28 at 5 29 55 PM" src="https://github.com/user-attachments/assets/ad5b13c5-11a7-4fa4-a074-a519521641da" /> <img width="485" height="201" alt="Screenshot 2026-05-28 at 5 28 36 PM" src="https://github.com/user-attachments/assets/9cd2c138-92f5-4ff2-bf8f-21cdbeff0b79" /> ### After <img width="343" height="253" alt="Screenshot 2026-05-28 at 5 29 40 PM" src="https://github.com/user-attachments/assets/56a4dca7-f0a1-4530-8c89-3c4773b90486" /> <img width="420" height="206" alt="Screenshot 2026-05-28 at 5 29 22 PM" src="https://github.com/user-attachments/assets/d118340a-955e-4483-9888-4b566f59b931" /> --------- Co-authored-by: Anthony Eid <anthony@zed.dev> Co-authored-by: Anthony Eid <56899983+Anthony-Eid@users.noreply.github.com> |
||
|
|
cb06458cf8 |
git: Fix .git directory being removed from watcher when excluded via file_scan_exclusions (#57895)
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 #57888 Commit `c3f05a7060d75eae1b168434d299389f5fcdbdf2` introduced the bug on #50412 . This change modified the `remove_path` function to also remove the path from the watcher: https://github.com/zed-industries/zed/blob/356c8cae072a0288da786b5ac010ce3f0d532ea1/crates/worktree/src/worktree.rs#L3218-L3220 And when a user modified the global setting and doesn't include `.git` in it, like: ```jsonc // ~/.config/zed/settings.json { "file_scan_exclusions": ["foo"] } ``` But then includes it on their local project settings: ```jsonc // ~/my/local/project/.zed/settings.json { "file_scan_exclusions": ["**/.git"] } ``` It causes zed to stop watching for changes on `.git` Release Notes: - Fixed bug where zed stopped watching change on `.git` directory if it was added to the project local `file_scan_exclusions` |
||
|
|
23237ac456 |
Improve didChangeWatchedFiles handler performance (#59078)
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: John Tur <john-tur@outlook.com> Co-authored-by: Ben Kunkle <ben@zed.dev> |
||
|
|
7a469725d3 |
Refactor BufferDiff to allow multiple diffs to share the same base text buffer (#58266)
This PR changes how base texts are managed by the `buffer_diff` crate, to enable keeping two diff entities alive that share the same base text buffer entity. Previously, each diff owned its own base text buffer and edited it when calling `BufferDiff::set_snapshot`, so the only way to reuse the same base text between two diffs was to have two independent buffers for it, which is pretty inefficient. After this PR, each diff still has a base text buffer, but `set_snapshot` doesn't edit it. Instead, that responsibility moves into the caller. For updating the base text buffer, this PR also introduces a new pair of APIs, `Buffer::snapshot_with_edits` and `Buffer::fast_forward`, which allow us to move the parsing of the new base text into the background and then install the new syntax tree synchronously on the foreground. The git store uses the low-level APIs `set_snapshot` and `fast_forward` directly, and manages the head text and index text buffers itself (garbage-collecting them when they're no longer needed); this enables adding an `open_staged_diff` API which returns a diff between the managed index buffer and the managed head buffer (the latter is also used for the uncommitted diff's base text). Other downstreams don't need to reuse a base text buffer, and those have been migrated to use the high-level `set_base_text` API, which now calls `set_snapshot` and `fast_forward` internally, with a guard to prevent concurrent updates. Another change worthy of note is that we now always diff the old base text with the new base text to create `snapshot_with_edits`. There are also some incidental bug fixes: - Fixed an issue where a dangling weak unstaged diff could stick around in the git store forever - Restored the `IndexMatchesHead` optimization that had become inoperative in the remote case - Fixed a crash in the multibuffer due to the handling of `BufferDiffEvent::LanguageChanged`, which could cause the multibuffer to have transforms that were inconsistent with the diff base text. 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 ZED-81P Release Notes: - Fixed a rare crash that could occur while using the uncommitted diff. --------- Co-authored-by: Ben Kunkle <ben@zed.dev> Co-authored-by: Anthony Eid <hello@anthonyeid.me> |
||
|
|
6ca46fcf2c |
project: Normalize line endings in textual project search (#58628)
Release Notes: - Fixed an issue with project search on windows where multiline string searches would not work correctly due to newline differences |
||
|
|
2d18262735 |
Prevent auto-restart of language servers after Stop All Servers (#51468)
Release Notes: - When stopping all language servers, Zed will now no longer restart language servers when language files change until the user restarts all language servers explicitly |
||
|
|
51fd135b45 |
git: Further extract gitlib2 dependencies (#58280)
Extraction done from #53453 I removed the default Oid implementation we had and added support back for SHA264 back as well. I also removed the hex dependency and just added some of those functions we needed in house so we can avoid building yet another dependency 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 Release Notes: - N/A |
||
|
|
e39d014d2f |
lsp: Fix duplicate workspace/didChangeConfiguration notifications (#56853)
Editing the `lsp` section of `.zed/settings.json` caused two identical
`workspace/didChangeConfiguration` notifications to be sent to each
language server, e.g.:
// Send:
{"jsonrpc":"2.0","method":"workspace/didChangeConfiguration","params":{"settings":{"jetls":{"code_lens":{"references":true},"completion":{"method_signature":{"prepend_inference_result":true}},"full_analysis":{"debounce":2},"inlay_hint":{"block_end":{"min_lines":25}}}}}}
// Send:
{"jsonrpc":"2.0","method":"workspace/didChangeConfiguration","params":{"settings":{"jetls":{"code_lens":{"references":true},"completion":{"method_signature":{"prepend_inference_result":true}},"full_analysis":{"debounce":2},"inlay_hint":{"block_end":{"min_lines":25}}}}}}
`maintain_workspace_config` observed `SettingsStore` directly while
`on_settings_changed` also fed the same loop through
`request_workspace_config_refresh`, so every settings change drove the
refresh loop twice and sent two identical
`workspace/didChangeConfiguration` notifications to each language
server.
Drop the in-loop observer and drive the loop from
`external_refresh_requests` alone. Settings changes still arrive via
`on_settings_changed -> request_workspace_config_refresh`, and toolchain
activation continues to use the same channel.
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 #ISSUE
Release Notes:
- Fixed language servers receiving duplicate
`workspace/didChangeConfiguration` notifications on every settings
change.
|
||
|
|
bf9255e53a |
ep: Fix agent edits triggering edit predictions due to diagnostic refresh (#57832)
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 #ISSUE Release Notes: - N/A or Added/Fixed/Improved ... --------- Co-authored-by: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com> |
||
|
|
9c70888039 |
Update git2 to 0.21.0 and add support for SHA-256 object formatted repos (#57587)
Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [ ] ~Unsafe blocks (if any) have justifying comments~ (N/A) - [x] The content is consistent with the [UI/UX checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) - [ ] Tests cover the new/changed behavior (didn't add new test for parsing SHA-256 - not sure if would be desired) - [x] Performance impact has been considered and is acceptable Closes #24070 Upgrades git2 from 0.20.1 to 0.21.0 with the `unstable-sha256` feature - adds ability to open and work with git repositories using the SHA-256 object format. `Oid::from_str` now detects 64-char hex strings to parse SHA-256 OIDs correctly. Also adapts to breaking API changes in 0.21.0: `Remote::url()` and `Commit::message()` both now return `Result`. Release Notes: - Added support for opening SHA-256 object format git repositories |
||
|
|
16ede263e4 |
git: Degrade gracefully when refreshing git state (#57292)
This PR changes the git store's `compute_snapshot`, which runs to update state that depends on the contents of `.git`, to degrade gracefully when fetching individual pieces of state fails. For example, when fetching the list of branches fails, instead of returning early from the function (leaving the previous git state snapshot in place with stale state), we continue with an empty list of branches. This prevents failures of individual git commands from making the entire git UI get stuck indefinitely. 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) - [ ] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable Closes #ISSUE Release Notes: - Fixed an issue where failing to fetch branches using the git CLI would prevent other git-related state from being updated. |
||
|
|
955a5f5ba3 |
Deprecate and migrate ACP extensions (#57133)
Self-Review Checklist: - [X] I've reviewed my own diff for quality, security, and reliability - [N/A] 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) - [ ] Tests cover the new/changed behavior - [X] Performance impact has been considered and is acceptable Release Notes: - Removed support for ACP extensions. Installed ACP extensions will be migrated to use the ACP servers as provided by the ACP registry instead. --------- Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com> Co-authored-by: Marshall Bowers <git@maxdeviant.com> |
||
|
|
3288a3463f |
acp: Prevent registry loading from hanging indefinitely (#56108)
Helps #51567 Refs #54531 Summary: - Add total timeouts for ACP Registry JSON fetches and icon fetches, including response body reads. - Download registry icons concurrently and keep icon failures non-fatal, so a blocked icon CDN does not delay registry availability by one timeout per agent. - Surface the stored registry fetch error in the ACP Registry empty state and add a retry action. This addresses cases where the registry request, or one of the icon requests, never finishes. It does not make blocked networks succeed, but it prevents the UI from sitting on `Loading registry...` indefinitely and gives the user something actionable instead. Test plan: - `git diff --check HEAD~1..HEAD` - `cargo fmt --check --package project --package agent_ui` - `cargo check -p project` - `cargo check -p agent_ui` - `cargo test -p project --features test-support registry_refresh_` Release Notes: - Fixed the ACP Registry getting stuck on loading when registry or icon requests hang. --------- Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com> Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com> |
||
|
|
17c284803f |
Improve bare repo support (#55153)
Fixes https://github.com/zed-industries/zed/issues/54830 This fixes a bugs where * when there's no main worktree, we treated the first linked worktree as main * the titlebar and sidebar showed two different things when opening a linked wortree directly When there's no main worktree, our "project group key" will be the bare repo path. For displaying this to the user, we try to present something meaningful: * If the bare repo is `foo.git`, we'll say "foo" * If the bare repo is "bar/.bare", we'll "bar" Release Notes: - Fixed bugs in Zed's sidebar and titlebar when editing in git worktrees created from bare repositories. |
||
|
|
0438bf5268 |
Rust 1.95 (#55104)
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 #ISSUE Release Notes: - N/A |