5d2df6acd596ca40aa86fb4a649ec4bc8d0dba34
39263
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
5d2df6acd5 |
Fix crash when dumping debug buffers in a collab session (#61616)
The `dev: dump input latency histogram` and `dev: dump accessibility tree` actions called `Project::create_local_buffer`, which panics on remote projects — so running either one as a guest in a collab session aborted the whole app. Both now use the async `Project::create_buffer` + `set_text` instead (the same pattern `open_log_file` uses), which routes through the collab protocol on remote projects. Since the collab-created buffer is visible to other participants, the latency report now includes a "Reported from <username>'s machine" line when the project is shared, using the collab username so we don't expose anything that isn't already shared with the session. While restructuring the handler I also split snapshotting from formatting: the histogram snapshot (and the delta baseline) is captured synchronously when the action fires, and the report string is built on a background task. The accessibility tree dump stays synchronous because gpui doesn't currently expose the captured tree data outside the window borrow, and adding public API for a debug action's JSON pretty-print didn't seem worth it. Release Notes: - Fixed a crash when running the `dev: dump input latency histogram` or `dev: dump accessibility tree` actions in a shared project. |
||
|
|
e2f35dd8c8 |
agent_ui: Fix selection mentions from "Add to Agent Thread" not opening files (#61621)
# Objective Fixes #59333. Selection mentions created with "Add to Agent Thread" could not be clicked to open the referenced file, while selection mentions created by pasting were navigable. ## Solution The ready selection-mention crease did not receive its `MentionUri` or `Workspace`, so `MentionCrease` could not install its click handler. Pass the workspace through the action-completion callback and provide both values to the shared crease renderer, enabling its existing navigation behavior. ## Testing I tested these changes locally. ## 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 Before: https://github.com/user-attachments/assets/8dd4a2d0-4b22-4fb3-8777-cf97b6436b91 After: https://github.com/user-attachments/assets/cff1cdb3-804a-45d8-a9c5-fdd8b35b6f8f --- Release Notes: - Fixed selection mentions added with "Add to Agent Thread" not opening their referenced files. |
||
|
|
94cb83400b |
gpui_windows: Align inactive GPUI popup behavior on Windows with other platforms (#61411)
*As an LLM was used to translate the PR message, the original text is included alongside the translation in accordance with the contributing guidelines. # Objective > On Windows, GPUI accepted `WindowKind::PopUp` and `focus: false`, but the window creation path ignored both options. This caused two problems with the notification popup shown when an agent finished its work: > > * When another window had focus, the popup could appear behind it. > * When Zed had focus, the popup could steal focus. > > This pull request applies `WindowKind::PopUp` and `focus: false` to windows on Windows, bringing popup behavior in line with other operating systems. Windows版GPUIでは、`WindowKind::PopUp`と`focus: false`を指定しても、それらのオプションが実際のウィンドウ生成処理では無視されていました。そのため、エージェントの作業が完了したときに表示される通知で次のような問題が発生していました。 - ほかのウィンドウにフォーカスがある場合にポップアップがほかのウィンドウの背後に隠れてしまう - Zedにフォーカスがある場合はポップアップがフォーカスを奪ってしまう このプルリクエストでは、Windows上でも`WindowKind::PopUp`と`focus: false`をウィンドウに反映させるようにし、ポップアップの挙動をほかのOSと一致させます。 ## Solution > This PR updates popup creation in GPUI on Windows to match the behavior on other platforms. When you specify `WindowKind::PopUp` and `focus: false`, GPUI now keeps the popup above other windows without stealing focus. > > Keeping a `focus: false` popup above other windows caused the IME to commit text under composition when the popup appeared. This PR also fixes that issue. Windows版GPUIのポップアップの生成処理をほかのプラットフォームの挙動と一致するように変更しました。このPRでは、`WindowKind::PopUp`と`focus: false`を指定したときにポップアップウィンドウを最前面に表示し、フォーカスを奪わないようにしました。 また、`focus: false`のポップアップが最前面に表示されるようにしたことで、ポップアップが表示されたときにIMEで入力中のテキストが意図せず確定されるようになってしまったため、それに対する修正も含まれています。 ## Testing > I built Zed on Windows and displayed a test agent notification to verify the following: > > * The popup stays above other windows when another window has focus. > * When Zed has focus, a popup with `focus: false` does not steal focus or interrupt IME input. > * The buttons in the popup remain clickable. Windows上でZedをビルドし、テスト用のエージェント通知を表示して次の項目をテストしました。 - ほかのウィンドウにフォーカスがある場合でもポップアップが最前面に表示される - Zedにフォーカスがある場合に`focus: false`のポップアップがフォーカスを奪わず、IMEを使った入力も阻害しない - ポップアップ内のボタンをクリックできる ## 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 > Note: I added a button to display an agent notification for testing in this video, but this PR does not include that button. ※この動画ではテスト目的でエージェント通知を表示するボタンを追加していますが、このPRの変更には含まれていません。 ### Before The popup window is hidden when another window has focus: https://github.com/user-attachments/assets/5312729b-1409-4c81-a169-dd031099059b A popup with `focus: false` steals focus: https://github.com/user-attachments/assets/dd1ac2a2-d5e8-4f8f-bc47-6cc659a10951 ### After The popup window stays on top even when another window has focus: https://github.com/user-attachments/assets/af058921-14fc-4ca5-9698-758202c4c888 A popup with `focus: false` does not steal focus or interrupt text input: https://github.com/user-attachments/assets/9bc487c6-ae68-4ec0-9073-1257b91e06a9 --- Release Notes: - Fixed Windows agent notifications appearing behind other windows, stealing input focus, or committing active IME composition. --------- Co-authored-by: John Tur <john-tur@outlook.com> |
||
|
|
0222e451f9 |
Fix: prevent completion labels and docs from being truncated (#61324)
# Objective - Fixes #60374 ## Solution - Moved the `documentation_label` from the `ListItem::end_slot` into the main `h_flex` layout alongside the `main_label`. - Added `.flex_shrink(1.0)` and `.truncate()` to the documentation container. - To allow it to shrink gracefully when space is tight. - Removed `.w_full()` from the main label's container. - To prevent it from aggressively occupying all available horizontal space, allowing the layout to balance the width between the label and the documentation. ## Testing - Visual and layout fixes tested manually by verifying the completion menu in `settings.json`. - All unit tests in the affected crate passed: `cargo test -p editor`. ## 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 ### Visual change <img width="813" height="314" alt="スクリーンショット 2026-07-20 143707" src="https://github.com/user-attachments/assets/1daa3fa4-a479-465a-b7fd-cc803242c8a2" /> --- Release Notes: - Fixed(CompletionsMenu): prevent completion labels and docs from being truncated. --------- Co-authored-by: Nathan Sobo <nathan@zed.dev> |
||
|
|
fb813f70d6 |
worktree: Suppress bare .git events explained by filtered sibling events (#61636)
Fixes an infinite git-rescan loop on Windows introduced by #59876. On Windows, creating or deleting a file directly inside .git updates the directory's last-write time, so ReadDirectoryChangesW reports a bare .git Changed event alongside the file's own event. Since #59876, bare .git events schedule a git rescan (to cope with coalesced FSEvents on macOS), so every filtered-out lock-file event still triggered a rescan through its paired bare event. Because a rescan's own `git diff --numstat HEAD` can take .git/index.lock (even under --no-optional-locks, e.g. in jj-colocated repos whose index never refreshes clean), each rescan re-triggered the next one, spawning ~9 git processes per cycle, ~4 cycles/sec, indefinitely. Bare .git events are now deferred while processing an event batch and only trigger a rescan when the batch contains no filtered event for the same git dir that explains the directory change. A standalone bare .git event (the macOS coalescing case #59876 addressed) still triggers a rescan, as does any batch containing a meaningful .git change. Release Notes: - N/A or Added/Fixed/Improved ... |
||
|
|
73be80748b |
Add sextant glyph support to terminal rendering (#51072)
The Zed integrated terminal shows a broken QR code for apps with Expo SDK 55. This PR custom-paints the terminal block and sextant glyphs used for QR codes rather than relying on font glyphs. | SDK 55 Before | SDK 55 After | SDK 55 in Ghostty | | --- | --- | --- | | <img width="581" height="536" alt="Zed Nightly" src="https://github.com/user-attachments/assets/11054401-e947-4628-918a-0088042ccbf9" /> | <img width="563" height="535" alt="Zed dev build" src="https://github.com/user-attachments/assets/22e0bed3-9927-436d-8e0b-1ad0839f7bee" /> | <img width="576" height="502" alt="Ghostty" src="https://github.com/user-attachments/assets/c5f544d8-43e5-4dad-8bcd-8a36c401e9a7" /> | ### Other notes - Expo recently merged https://github.com/expo/expo/pull/46148, which causes Expo SDK 56 to fall back to the old QR code behavior when used in Zed. Once this PR merges, Expo can remove that fallback and use the compact QR code path in Zed again for Expo SDK 56+. | Current Fallback QR Code for SDK 54 and 56 | Fallback with this PR | | -- | -- | | <img width="744" height="684" alt="SCR-20260622-jwco" src="https://github.com/user-attachments/assets/414896aa-52bc-4de7-a6b9-59cd5af08de0" /> | <img width="616" height="752" alt="SCR-20260622-kfjh" src="https://github.com/user-attachments/assets/accbef7a-3365-480f-add3-08910141afa5" /> | This PR now also fixes TUIs in the integrated terminal for users using some fonts. | OpenCode w/ Monaco before change | OpenCode w/ Monaco after change | | --- | --- | | <img width="1512" height="982" alt="image" src="https://github.com/user-attachments/assets/a40f01a6-adf9-4e8b-909a-be53945eb813" /> | <img width="1512" height="982" alt="image" src="https://github.com/user-attachments/assets/b40bb22c-ef7e-466a-9bcf-46eb951087cd" /> | Finally, shade characters are now handled in the integrated terminal. | btop with tty graph before change | btop with tty graph after change | | --- | --- | | <img width="1516" height="863" alt="SCR-20260724-irpr-2" src="https://github.com/user-attachments/assets/afb77f01-6d3d-428a-b1be-7abb3d0e3d4d" /> | <img width="1516" height="876" alt="SCR-20260724-ises-2" src="https://github.com/user-attachments/assets/42262858-70da-4ba2-a5e6-96243fcfaadd" /> | #### This PR - Adds custom painting for terminal bitmap glyphs used by QR renderers: `█`, `▀`, `▄`, `▌`, `▐`, and U+1FB00..U+1FB3B sextants - Adds tests for handling sextants, blocks/half-blocks, and adjacent block merging Closes #50158 Closes #58830 Before you mark this PR as ready for review, make sure that you have: - [X] Added a solid test coverage and/or screenshots from doing manual testing - [X] Done a self-review taking into account security and performance aspects - [X] Aligned any UI changes with the [UI checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) Release Notes: - Fixed QR code rendering for Expo SDK 55 apps - Fixed rendering TUIs in the integrated terminal for some users --------- Co-authored-by: Kirill Bulatov <kirill@zed.dev> |
||
|
|
3b9b83b354 |
collab: Fix multiworkspace location out of sync bugs (#61598)
### Summary This PR fixes three small bugs that could cause a multi-workspace's reported location to be out of sync with its actual location, which causes following to break in multiplayer collaboration sessions. The first bug was that each child workspace's title bar within a multi-workspace had its own `cx.observe_window_activation` subscription that would set the associated child workspace's project location. This caused problems because it ran for all child workspaces instead of just the active workspace within the multi-workspace. The fix was moving `cx.observe_window_activation` to the `cx.observe_new` call in the `call` crate that tracks newly created windows/multi-workspaces. The second bug was caused by an incorrect `if` statement in a `MultiWorkspace` subscription that would return early if the window was active and the event emitted by `MultiWorkspace` wasn't `ActiveWorkspaceChanged`. This caused issues when the window was inactive because it would incorrectly set the active call's location to the wrong project. The fix was making the early return happen if the window wasn't active. The third bug was that every child `Workspace` also observed window activation and called `update_active_view_for_followers`. This allowed hidden workspaces to report their active view instead of only the active workspace. ### Testing I added a property test for bugs one/two and another prop test for bug 3 Release Notes: - collab: Fix out of sync following bugs |
||
|
|
27c897944c |
gpui: Fix images not being drawn with rounded corners when using ObjectFit::Cover (#61383)
# Objective Fixes #44339 ## Solution The issue was taking place as image bounds where larger than the view bounds. Hence, the rounding of the image happened outside the view bounds, hence the corners where not rounded. This solution changed the paint_image function in window.rs. Now, it takes in 2 parameters, image bounds and bounds of the area to be draw. Then, the function creates the tile field of PolychromeSprite by cropping the image to fit the area to be drawn. This ensures that the rounding happens correctly. ## Testing Testing was done as per the issue and results where verified visually. ## 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 <img width="1409" height="1030" alt="image" src="https://github.com/user-attachments/assets/3645b36d-f182-4853-bdfe-d66a4132d273" /> ## Release Notes: Fixed rounded corners not rendering on images when using ObjectFit::Cover --------- Co-authored-by: Christopher Biscardi <chris@christopherbiscardi.com> Co-authored-by: Nathan Sobo <nathan@zed.dev> |
||
|
|
69518271c9 |
workspace: Rename read-only tab controls from File to Tab (#61202)
## Context
The editor tab's read-only controls used "File" terminology in their
tooltips and the tab context menu ("Make File Read-Only", "Locked File",
"Read-Only File", etc.). This was misleading in two ways: the option
also appears on unsaved and non-file tabs that have no file on disk, and
the toggle only controls whether the buffer is editable in the editor,
it does not change filesystem permissions. This renames the labels to
lock/unlock "Tab" language, matching the lock icon shown when the tab is
toggled.
Closes #60079.
Behavior after the change :
[Screencast from 2026-07-17
15-35-30.webm](https://github.com/user-attachments/assets/5fb018cb-515f-449c-a57e-0c0bead250bd)
## How to Review
1 file changed:
**crates/workspace/src/pane.rs**
Renames three sets of user-facing strings, all pure text changes with no
behavior change. The read-only toggle button tooltips become "Unlock
Tab" / "This will make this tab editable" and "Locked Tab" / "This tab
is read-only". The tab tooltip meta label becomes "Read-Only Tab". The
context menu entry, whose label already depends on
`capability.editable()`, becomes "Lock Tab for Editing" (when currently
editable) and "Unlock Tab for Editing" (when currently read-only); the
click handler still calls `toggle_read_only`, so the mapping from label
to action is preserved.
## 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
- [ ] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Release Notes:
- Improved read-only tab controls to use "Tab" instead of "File" in
tooltips and the tab context menu, since the toggle affects editability
in the editor rather than filesystem permissions.
---------
Co-authored-by: Nathan Sobo <nathan@zed.dev>
|
||
|
|
127aa6dcd2 |
git_ui: Prevent Git panel bindings in repository selector (#61282)
# Objective Fix Git panel keybindings intercepting input intended for the repository selector. With Vim mode enabled, pressing `i` in the selector focused the commit-message editor instead of filtering repositories. Platform keybindings could also intercept printable input such as spaces. Fixes #57936 ## Solution Exclude the `GitRepositorySelector` context from the Git panel changes-list bindings in the macOS, Linux, Windows, and Vim keymaps. ## Testing Manually tested on macOS using a debug build with Vim mode enabled and a workspace containing two Git repositories ## 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 Git repository selector input being intercepted by Git panel keybindings, including in Vim mode. Co-authored-by: Nathan Sobo <nathan@zed.dev> |
||
|
|
8a24015e4f |
editor: Skip untitled buffers when saving a multi-buffer (#61380)
Closes #60041. ## Summary When Project Search results contain both a saved file and an untitled buffer, running `workspace: reload` did nothing (quitting hit the same path). The log showed: ``` ERROR [.../workspace.rs] buffer doesn't have a file ``` ## Root cause The Project Search results view is an `Editor` over a multi-buffer, and its `Item::save` delegates to `Editor::save`. For a multi-buffer, `Editor::save` collects every dirty buffer and calls `Project::save_buffers`. An untitled excerpt has no file, so `BufferStore::save_buffer` returns `Err("buffer doesn't have a file")`. That error propagates through `Pane::save_item` → `save_all_internal` → `prepare_to_close`, which then reports the workspace as not ready to close, so `reload`/quit silently aborts. A singleton untitled buffer avoids this because `Editor::can_save` returns `false` for it (the workspace routes it to `save_as`); for a multi-buffer, `can_save` is always `true`. ## Fix Exclude file-less (untitled) buffers when collecting the buffers to save for a multi-buffer. Untitled buffers can only be written via `save_as`, so a bulk multi-buffer save now persists the file-backed excerpts and leaves untitled ones untouched. This also addresses the same latent issue in other multi-buffer views (diagnostics, find-all-references) that can excerpt an untitled buffer. ## Testing - Added `test_save_multi_buffer_with_untitled_buffer_skips_untitled` in `crates/editor/src/items.rs`: it builds a multi-buffer over a file-backed buffer and an untitled buffer (both dirty), then asserts `save` succeeds, the file-backed buffer is persisted, and the untitled buffer stays dirty. Fails before this change (`buffer doesn't have a file`), passes after. - `cargo test -p editor --lib save` (13 tests) and `cargo test -p search --lib project_search` (22 tests) pass. - `./script/clippy -p editor` is clean. Manual repro (before): new untitled buffer with text → Project Search for a term matching both it and a saved file → `workspace: reload` → no-op with `buffer doesn't have a file` in the log. After: reload proceeds. Release Notes: - Fixed `workspace: reload` and quitting silently doing nothing when Project Search results included an unsaved untitled buffer. |
||
|
|
907dd1f442 |
gpui_windows: Only flash the window once on request_attention (#61611)
The current behavior bothers me. Release Notes: - N/A |
||
|
|
8457a4ccf4 |
Opus 5 BYOK Support (#61596)
<img width="844" height="404" alt="Screenshot 2026-07-24 at 3 47 04 PM" src="https://github.com/user-attachments/assets/4691a246-bab9-4426-aa0b-6a7cfa2aa486" /> action support, and explicit thinking opt-out behavior. Adds Claude Opus 5 to the Anthropic and Amazon Bedrock BYOK providers, including its documented context and output limits, regional inference profiles, fast mode and comp Release Notes: - Added Claude Opus 5 support for Anthropic and Amazon Bedrock BYOK providers. |
||
|
|
76e43838aa |
editor: Fix sticky header drag cancels autoscroll (#53592)
In #52636 I seem to have introduced this bug, where mouse-down on a sticky header followed by an immediate mouse movements sometimes dropped the pending autoscroll request (to jump to the sticky header line): https://github.com/zed-industries/zed/blob/967ae5ea24376be68c41336fa0ff721f5ca5a3cf/crates/editor/src/scroll.rs#L453 Fixed by exiting early from `mouse_dragged` when `editor.has_autoscroll_request()`. What sometimes happened before this fix: https://github.com/user-attachments/assets/b6dd6650-b5f0-4ea1-ae70-9c4cf69e31a0 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: - Fixed bug where clicking on a sticky header would sometimes not jump to that line in the editor |
||
|
|
fe4f59add6 |
Add explicit OpenAI conversation compaction and fix Anthropic compaction (#61370)
# Objective Add explicit conversation compaction for OpenAI Responses API models, available through both direct OpenAI connections and Zed Cloud models. Keep finalized replacement context provider-neutral and separate from the lifecycle events emitted while automatic compaction is in progress. ## Solution - Add opt-in explicit compaction support to the `LanguageModel` trait. - Separate streamed `CompactionUpdate` lifecycle events from finalized `CompactedContext`. - Represent provider-native compacted context as an opaque, versioned state owned by the originating provider. - Construct compact requests through the same OpenAI request conversion used for completions, then narrow the request to fields supported by `/responses/compact`. - Preserve and validate the complete canonical replacement window returned by OpenAI. - Replay the replacement window before messages sent after compaction, without resending the superseded transcript. - Support explicit compaction through both the direct OpenAI provider and `CloudLanguageModel`. - Update automatic OpenAI and Anthropic compaction to use the same finalized context representation. - Reject empty, malformed, incorrectly versioned, and incorrectly owned provider state. The corresponding Cloud change adds the `/completions/compact` proxy route: https://github.com/zed-industries/cloud/pull/3099. The downstream Delta UI integration is https://github.com/zed-industries/delta/pull/1739. ## Testing - `cargo nextest run -p anthropic -p open_ai -p language_models_cloud` - `cargo check -p language_models --tests` - `cargo fmt --all --check` - `git diff --check` The focused tests cover request construction, canonical-window preservation and replay, direct and Cloud transports, automatic compaction lifecycle events, malformed provider state, provider ownership, format compatibility, and HTTP failure handling. ## 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: System messages are now sent through the `instructions` field in OpenAI Responses API requests. |
||
|
|
413b457870 |
worktree: Reload git state when a watcher rescan covers a repository (#61541)
# Objective When the OS file watcher loses sync (e.g. its event queue overflows under heavy fs churn), it drops pending events and reports a single `Rescan` event for the watched root. Git changes hidden behind such a rescan were silently lost, leaving the git panel and branch indicator stale until something else touched `.git`. Contributes to #13176. May fix #60102, though that report predates #60660 and may already be addressed by it on nightly (see Related PRs below). Two bugs caused this, and they masked each other: 1. **A rescan never triggered a git reload.** The `Rescan` event's path is the worktree root, not something inside `.git`, so it never populated `dot_git_abs_paths` in `process_events` — and since `.git` is excluded from entry scanning, the rescan produced no `.git` events either. The dropped git changes were simply never picked up. 2. **Re-scanning reset `git_dir_scan_id` to 0.** The snapshot diff detects git changes by comparing scan ids, so re-inserting the repository with a fresh id could wipe out a bump made earlier in the same scan cycle, swallowing the corresponding `UpdatedGitRepositories` signal. The masking is why these fixes land together rather than as two PRs: the root-rescan case in `test_dot_git_dir_event_does_not_suppress_children` only passed on `main` because the buggy scan-id reset made the snapshot diff fire spuriously. Fixing either bug alone turns that (currently green) test red. ## Solution - `process_events`: a `Rescan` event now schedules a git state reload for every repository whose git directory (`dot_git`, `common_dir`, or `repository_dir`) lies under the rescanned path, covering linked worktrees and gitfile repositories, including git dirs watched outside the worktree root. - `insert_git_repository_for_path`: carry the existing `git_dir_scan_id` forward when re-inserting a repository instead of resetting it to 0. Deliberately *not* bumped either: re-insertion is snapshot bookkeeping, not evidence of a git change — bumping would trigger spurious full reloads on non-lossy paths (explicit refreshes, path-prefix scans). Only `update_git_repositories` claims that git state changed. - `changed_repos`: a `debug_assert` enforcing that `git_dir_scan_id` never regresses, so future violations of this invariant fail loudly in tests instead of manifesting as a stale git panel. ## Testing New fault-injection infrastructure and tests: - `FakeFs::simulate_watcher_overflow` models the kernel's watch queue overflowing: buffered (undelivered) events are discarded and replaced by a single `Rescan` for the given root, mirroring FSEvents `kFSEventStreamEventFlagMustScanSubDirs`, inotify `IN_Q_OVERFLOW`, and Windows `ERROR_NOTIFY_ENUM_DIR`. - `test_watcher_overflow_rescan_reloads_git_state`: a git change whose events are lost to an overflow must still be picked up via the rescan (reproduces bug 1; fails on `main`). - `test_git_update_in_same_batch_as_rescan_is_not_lost`: a git event processed in the same batch as a rescan must not lose its scan-id bump to the repository re-insertion (reproduces bug 2; fails on `main`). - `test_random_git_updates_with_watcher_overflows`: randomized property test (100 iterations) asserting that every git state change is eventually signaled via `UpdatedGitRepositories` under random event batching, delays, and overflows. Fails on `main` within the first few seeds. - `test_random_worktree_changes` now also injects watcher overflows, extending its existing convergence property to rescan reconciliation of worktree entries (this already passed; the injection guards it going forward). Full `worktree` and `fs` suites pass. Verified the directed tests exercise the intended code paths via trace logging (the same-batch test hits `update_git_repositories` stamping followed by re-insertion, distinct from the overflow test where no `.git` event arrives at all). ## Related PRs The recent stale-git-state reports trace back to three distinct mechanisms that share one symptom. This PR addresses the third: - **Events never generated** — #60660 (merged, in this PR's base): Linux's non-recursive watcher missed nested `refs/` directories, so external commits/fetches produced no events at all. That PR (together with #60590, which explicitly rescans after Zed-initiated reset/fetch and touches only `git_store.rs`) fixed #60348. No overlap with this PR; a merge against current `main` is clean, and the refs-watching tests are disjoint from the overflow/rescan tests added here. - **Events coalesced** — #59876 (open, complementary): FSEvents can merge `.git` child events into a bare `.git` `Changed` event; the signal arrives, in a shape Zed ignores. @RemcoSmitsDev's review comment there describes this PR's failure mode and calls the two fixes complementary; this is effectively the follow-up promised in that comment. Both PRs touch the same region of `process_events`, so whichever lands second needs a trivial rebase, and #59876 flips the bare-`.git` expectation in `test_dot_git_dir_event_does_not_suppress_children` Case 2, which this PR preserves. - **Events dropped** — this PR: the watcher generated events but lost them to a queue overflow, and the resulting `Rescan` did not reach the git reload path. #59976 and #60098 (merged) reduced how often this happens; this PR makes git state recover correctly when it does. ## 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 the git panel and branch indicator showing stale state after heavy file-system activity caused the file watcher to lose events |
||
|
|
3d7c8e732e |
search: Escape seeded buffer search query in regex mode (#57748)
## What When `seed_search_query_from_cursor` is enabled and regex mode is active, the selected text is used verbatim as the regex pattern. This means selecting text like `z.d` seeds the regex `z.d`, where `.` acts as a wildcard — matching `zed`, `zXd`, etc. — rather than only the literal string the user selected. Fixes #57253. ## Why it was broken `search_suggested()` in `BufferSearchBar` retrieves the raw selection text from `query_suggestion()` and passes it directly to `search()`. There was no escaping step, even when `default_options` had `SearchOptions::REGEX` set. ## Fix Run the seeded suggestion through `regex::escape()` before passing it to `search()` when regex mode is enabled. This mirrors the identical pattern already used in `crates/vim/src/normal/search.rs:485`. ```rust // Before let search = self .query_suggestion(seed_query_override, window, cx) .map(|suggestion| { self.search(&suggestion, Some(self.default_options), true, window, cx) }); // After let search = self .query_suggestion(seed_query_override, window, cx) .map(|suggestion| { let suggestion = if self.default_options.contains(SearchOptions::REGEX) { regex::escape(&suggestion) } else { suggestion }; self.search(&suggestion, Some(self.default_options), true, window, cx) }); ``` ## Test Added `test_seeded_query_is_escaped_in_regex_mode` in `buffer_search.rs`. It creates a buffer with `"z.d\nzed\n"`, enables regex mode, selects `z.d`, seeds the search, and asserts: - The query text becomes `z\.d` (escaped), not `z.d` - Exactly 1 match is highlighted (the literal `z.d`), not 2 The `regex` crate was already a workspace dependency and is already used in the `search` crate transitively; this adds it explicitly to `crates/search/Cargo.toml`. Release Notes: - Fixed regex search seeded from cursor/selection matching more than the selected text when the selection contained regex special characters (e.g. `.`, `*`, `(`) --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com> |
||
|
|
ca267a68a3 |
gpui: Fix deadlock in performance profiler and reenable it (#61584)
### Summary PR #58942 disabled the performance profiler within Zed because there was a race condition that caused Zed to hang forever due to a deadlock involving the foreground thread. This PR fixes the deadlock and re-enables the performance profiler. The deadlock happened because `ThreadTimings::drop()` locks `GLOBAL_THREAD_TIMINGS`, and that drop could run in places where `GLOBAL_THREAD_TIMINGS` was already locked: the collection paths (`get_all_timings`, `take_all_stats`, `set_trace_enabled(false)`) held the global lock while upgrading and then dropping per-thread `Arc<GuardedTaskTimings>` handles. If a worker thread exited in that window (e.g. GCD reclaiming an idle thread), the collector inherited the last strong reference, and dropping it ran `ThreadTimings::drop` -> `GLOBAL_THREAD_TIMINGS.lock()` reentrantly on the same thread. The spinlock is not reentrant, so the thread spun forever while holding the lock, hanging every other thread that touched the profiler. The fix: hold `GLOBAL_THREAD_TIMINGS` only long enough to upgrade the `Weak` handles (`upgraded_thread_timings()`), and release it before any per-thread buffer is locked, copied, or dropped. A last-reference drop now always runs with the global lock free. As a side benefit, the up-to-16MiB per-thread buffer copies no longer happen under the global lock. ### Diagram ```mermaid sequenceDiagram participant C as Collector thread (get_all_timings) participant G as GLOBAL_THREAD_TIMINGS (spin::Mutex) participant T as Worker thread (exiting) Note over T: holds the only strong Arc<br/>in its THREAD_TIMINGS TLS C->>G: lock() — guard held for entire collection C->>C: Weak::upgrade() (strong: 1 → 2) T->>T: thread exits, TLS destructor drops its Arc (strong: 2 → 1) C->>C: temp Arc dropped at end of iteration (strong: 1 → 0) C->>C: ThreadTimings::drop() runs on collector thread C->>G: lock() again — already held by this thread Note over C,G: spin lock is not reentrant → spins forever,<br/>every other profiler user spins behind it Note over C,T: Fix: upgrade all Weaks under the lock, release it,<br/>then lock/copy/drop per-thread handles — the reentrant<br/>drop can now only ever run with the global lock free ``` Release Notes: - Fixed a deadlock in the performance profiler and re-enabled it (`zed: open performance profiler`) |
||
|
|
025bf6bf70 |
Treat blank spawn_agent session IDs as absent (#60893)
# Objective Fix `spawn_agent` calls that provide an empty or whitespace-only `session_id`. Currently, an empty string is deserialized as a real session id, so the tool attempts to resume a session with an empty id instead of starting a new subagent session. This can happen when callers serialize an optional `session_id` field as `""`. Related: Refs #55987. This addresses one concrete session-id failure mode described there, but that issue also covers broader OpenAI-compatible provider/subagent reliability concerns. ## Solution - Add custom deserialization for `SpawnAgentToolInput.session_id`. - Treat omitted, `null`, empty, and whitespace-only values as `None`. - Preserve existing behavior for non-empty `session_id` values, so follow-up calls still resume an existing subagent session. - Clarify the field docs. - Add a regression test covering omitted, `null`, empty, whitespace-only, and non-empty values. ## Testing Tested locally on macOS: - `RUSTUP_TOOLCHAIN=1.95.0 cargo fmt --manifest-path zed/Cargo.toml --package agent --check` - `RUSTUP_TOOLCHAIN=1.95.0 cargo test --manifest-path zed/Cargo.toml -p agent -p gpui_macos --features gpui_macos/runtime_shaders deserializes_blank_session_id_as_absent` - `RUSTUP_TOOLCHAIN=1.95.0 cargo build --manifest-path zed/Cargo.toml -p zed -p gpui_platform --features gpui_platform/runtime_shaders` - `RUSTUP_TOOLCHAIN=1.95.0 cargo clippy --manifest-path zed/Cargo.toml -p agent -p gpui_macos --features gpui_macos/runtime_shaders --tests -- -D warnings` The local build uses runtime shaders because this machine does not have the full Xcode Metal CLI toolchain available. CI should cover the standard build matrix. ## 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 `spawn_agent` handling so blank `session_id` values are treated as absent and start a new subagent session. --------- Co-authored-by: Bennet Bo Fenner <bennetbo@gmx.de> Co-authored-by: Bennet Bo Fenner <bennet@zed.dev> |
||
|
|
982e4c3e38 |
agent_ui: Fix agent terminal close behavior with keyboard shortcuts (#58217)
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 What: - Closing the active terminal from the sidebar activated the remaining terminal.But closing a terminal with Ctrl-D could leave the agent panel in an uninitialized `Zed Agent` state instead of activating the remaining terminal. <img width="804" height="380" alt="image" src="https://github.com/user-attachments/assets/eaa67c6e-7f3d-4a1c-b72d-9cabfaab872b" /> How: - Terminal exits emit `TerminalCloseRequested`. - The sidebar handles that request through the same close path used by the sidebar close button. - Neighbor activation, draft fallback, metadata cleanup, and linked-worktree/ archive handling stay centralized in the sidebar close flow. Added test coverage for closing an active terminal via terminal exit and activating the remaining terminal neighbor. Testing: - `cargo check -p agent_ui` - `cargo check -p sidebar` - Manually verified Ctrl-D terminal close behavior with multiple agent threads/terminals Release Notes: - Fixed closing an agent terminal with Ctrl-D leaving the agent panel uninitialized instead of activating the remaining terminal |
||
|
|
29fb1fc131 |
agent: Add agent.compaction_model setting for context compaction (#60012)
# Objective
Add a new `agent.compaction_model` setting that lets users specify a
separate language model for context compaction (`/compact` and
auto-compaction), independent of the thread's active conversation model.
Compaction is just summarization — there's no reason to pay Opus prices
for it when a cheaper model does the job faster. We've also seen
reasoning models misbehave on this task (empty responses, repetition
loops at high effort), so picking a dedicated non-reasoning model for
compaction is useful.
## Solution
- New `compaction_model: Option<LanguageModelSelection>` field in
`AgentSettingsContent` and `AgentSettings`, mirroring
`thread_summary_model`.
- New `compaction_model: Option<ConfiguredModel>` slot on
`LanguageModelRegistry` with `select_/set_/compaction_model()` trio,
mirroring the existing pattern. The setter deliberately does **not**
emit a registry event in v1; callers read the slot lazily at compaction
time.
- New `Thread::compaction_model(&self, cx: &App)` helper that returns
the configured model or falls back to `self.model()`. Two call sites —
`Thread::compact` and `perform_compaction_if_needed` — now go through
this helper instead of reading `self.model()` directly.
- `build_compaction_telemetry` accepts the compaction model explicitly
so the `model` field reflects the model that actually streamed the
request. `max_tokens` still derives from `thread.model()` (threshold
semantics are unchanged).
- Documentation updated at `docs/src/ai/agent-settings.md` (new
user-facing setting).
**Example:**
```json
{
"agent": {
"default_model": {
"provider": "anthropic",
"model": "claude-opus-4-6"
},
"compaction_model": {
"provider": "anthropic",
"model": "claude-sonnet-4-5"
}
}
}
```
**Resolution chain:**
```
agent.compaction_model (if set & available)
→ thread.model() (always available, current behavior)
```
**Behavior change:**
| Trigger | Before | After |
| --- | --- | --- |
| Manual `/compact` | Uses `thread.model()` | Uses
`agent.compaction_model` if set & available; else `thread.model()` |
| Auto-compaction | Uses `thread.model()` | Same as above |
| `/compact` when thread has no model | `NoModelConfiguredError` |
Succeeds if `compaction_model` resolves |
| `compaction_model` configured but provider missing / model id unknown
| n/a | Falls back to `thread.model()` and logs a one-time warning |
**Explicit non-goals:**
- No `Event::CompactionModelChanged`(no consumer; the `_cx` parameter on
`set_compaction_model` is intentionally accepted for future use).
- No GUI selector (consistent with all other feature-specific models).
- No per-profile override.
- No runtime API-error fallback — only config-time failure (provider not
registered, model id not in `provided_models`) triggers fallback. This
matches every other feature-specific model.
- No change to threshold calculation, auto-compact trigger, or
`COMPACTION_PROMPT`.
- No propagation to subagent threads.
## Testing
3 new unit tests in `crates/agent/src/thread.rs::tests`:
- `test_compaction_uses_configured_compaction_model` — manual `/compact`
routes to the configured model; thread's primary model receives no
request; telemetry reflects the configured model.
- `test_compaction_falls_back_when_compaction_model_unavailable` —
configured-but-unresolvable falls back to `thread.model()`; telemetry
reflects the fallback model.
- `test_auto_compaction_uses_compaction_model` — auto-compaction
triggered by threshold honors the same setting.
All 14 existing compaction tests still pass. Test suites in
`crates/agent_settings`, `crates/language_model`,
`crates/settings_content`, `crates/agent_ui` unchanged. `cargo clippy`
clean on the changed crates.
**How reviewers can test:**
1. Add `agent.compaction_model` to `settings.json` with a cheaper model
than the thread's primary model, run `/compact`, observe the cheaper
model receives the request.
2. Set `agent.compaction_model` to a non-existent provider/model id, run
`/compact`, observe fallback to thread model and a `log::warn!` line.
3. Trigger auto-compaction by reaching the threshold, observe it uses
`compaction_model`.
**Platforms tested:** local Linux (cargo check + cargo test on agent /
agent_settings / language_model / settings_content / agent_ui crates).
## 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 introduced
- [x] The content adheres to Zed's UI standards — N/A: settings-only
change, no UI touched
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable — model
resolution is an O(1) registry lookup, not on any hot path; no new work
in the streaming loop
Release Notes:
- agent: Add support for specifying which model is used for compaction
(`agent.compaction_model`)
---------
Co-authored-by: Bennet Bo Fenner <bennetbo@gmx.de>
Co-authored-by: Bennet Bo Fenner <bennet@zed.dev>
|
||
|
|
e387a55757 |
agent: Show effort selector for anthropic compatible providers (#61579)
Follow up to #57207 Release Notes: - agent: Show reasoning effort selector for anthropic compatible providers if model supports adaptive thinking |
||
|
|
8d0742b017 |
Fix adding breakpoint/bookmark via gutter context menu using the wrong row (#59269)
# Objective Fixes #59265 ## Solution Use `display_point_to_anchor` to properly convert `DisplayRow` to `Anchor`, instead of manually constructing `Point` directly as done currently. ## Testing - Tested manually, see video in issue - Tested on 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) - [ ] 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 the gutter context menu adding breakpoints/bookmarks to the wrong row in multibuffers. --------- Co-authored-by: dino <dinojoaocosta@gmail.com> |
||
|
|
af57f1732c |
acp: Update agent-client-protocol SDK to 2.0.0 (#61570)
This isn't ACP v2, but just a new version of the SDK where we had to do some breaking changes + cleanups. Release Notes: - N/A |
||
|
|
c9142fae21 |
repl: Show add-cell controls in empty notebooks (#61329)
## Objective When a notebook has no cells, the editor renders a blank pane with no visible way to add one. Cells can only be added via the toolbar icons or keybindings, which aren't discoverable from an empty editor — so a newly created `.ipynb` looks broken. This is the follow-up direction suggested in #61296. ## Solution Render an empty-state in the editor body when the notebook has no cells, with "Add code cell" / "Add markdown cell" buttons (dispatching the existing `add_code_block` / `add_markdown_block` handlers), matching the affordance VSCode provides. ## Testing Tested locally on macOS with the notebook feature enabled (`LOCAL_NOTEBOOK_DEV=1`): - Opening an empty `.ipynb` shows the empty-state instead of a blank pane. - Clicking "Add code cell" inserts an editable code cell and marks the tab dirty. ## Showcase **Before** — empty notebook renders a blank pane:  **After** — empty notebook shows add-cell controls:  Clicking "Add code cell" inserts a cell:  Release Notes: - N/A --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Finn Evers <finn.evers@outlook.de> |
||
|
|
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 |
||
|
|
b5e07a42c3 |
Use proper rules for merging language server settings (#61546)
Closes https://github.com/zed-industries/zed/issues/61524 https://github.com/zed-industries/zed/issues/60763 was a bogus issue: the semantic of root `language_settings` is the **default settings for all languages**, not a "magic string that gets applied when an `!x` exclusion is mentioned there". Thus, reverts https://github.com/zed-industries/zed/pull/60984 and redoes https://github.com/zed-industries/zed/pull/60000 in a correct way: more custom settings replace less custom ones, same applies to the language server settings. Instead of doing some odd `!x` manipulations, the right fix is to remove the old state as ```diff impl merge_from::MergeFrom for AllLanguageSettingsContent { fn merge_from(&mut self, other: &Self) { ... self.defaults.merge_from(&other.defaults); for language_settings in self.languages.0.values_mut() { + let language_servers = language_settings.language_servers.take(); language_settings.merge_from(&other.defaults); + language_settings.language_servers = language_servers; } for (language_name, user_language_settings) in &other.languages.0 { if let Some(existing) = self.languages.0.get_mut(language_name) { existing.merge_from(&user_language_settings); } else { let mut new_settings = self.defaults.clone(); + new_settings.language_servers = None; new_settings.merge_from(&user_language_settings); ``` After the final override is determined, `...` is expanded and `!x` entries are removed from the final list. Project settings override user settings, so it's possible that a certain language server is disabled by the user and re-enabled in the project: worktree trust mechanism is supposed to mitigate the security issues. More tests were added to cover all the cases. Release Notes: - Fixed project settings not re-enabling language servers |
||
|
|
f18ea2c94c |
Split VSCode and Zed keymap files (#61532)
Currently, Zed's "VSCode" keymap has certain discrepancies that are not changed for compatibility reasons, e.g. opening inline assistant is different in each editor. To simplify the transition, extract VSCode bindings its own keymap so in the future it's simpler to accept changes to each keymap separately. Caveat: people who had ever changed the keymap, will have VSCode keymap in their settings which will change their bindings slightly after this commit is released. I had to introduce more logic to `null` handling as had to somehow disable `ctrl-enter` on mac from spawning the inline assistant block for VSCode keymap (it's cmd-i there). Release Notes: - Split VSCode and Zed keymap files |
||
|
|
28605024d7 |
settings: Fix VS Code import appending duplicate file associations (#61355)
Closes #56536 ## What & why Running `zed: import vs code settings` more than once kept re-adding the same file extensions to `file_types`, so `files.associations` entries grew without bound: ```json "file_types": { "c": ["*.keymap", "*.keymap", "*.keymap"] } ``` The import merges the VS Code-derived settings into the user's existing settings, and `file_types` values were `ExtendingVec`s, whose `merge_from` appends every incoming value unconditionally. Per review feedback, instead of changing `ExtendingVec`'s merge semantics (it also backs ssh/wsl connections, `private_files`, etc.), this adds a new `ExtendingSet` type that actually behaves like a set, and switches `FileTypeMap`'s file associations to it: - Backed by an insertion-order-preserving `IndexSet`, so users' pattern order round-trips through the settings file unchanged (the import machinery diffs serialized old/new content to produce edits; a sorted set would reorder existing arrays). - Merging only accumulates new values, so re-importing an already-present association is a no-op. - Since it's a real set, deserialization also collapses duplicates that earlier imports already wrote into the settings file. - `ExtendingVec` and all its other users are untouched. ## Testing - Added a `test_vscode_import` case that re-imports an already-present `files.associations` entry and asserts the extension isn't duplicated. It fails before the change and passes after. - `cargo test -p settings -p settings_content -p language` pass. - `./script/clippy -p settings -p settings_content -p language -p recent_projects -p json_schema_store` is clean. Release Notes: - Fixed importing VS Code settings repeatedly adding duplicate `file_types` entries for `files.associations`. --------- Co-authored-by: Christopher Biscardi <chris@christopherbiscardi.com> |
||
|
|
d749d04034 |
Fix squashed Mermaid diagrams in markdown preview (#61260)
## Summary Wide Mermaid diagrams in Markdown Preview were forced through `max_w_full()`, so both width and height shrank to the pane and text became unreadable/blurry. There was no horizontal pan. Markdown Preview already sets `code_block_overflow_x_scroll: true` for fenced code blocks. Mermaid ignored that flag. This change gates layout on that style flag: - **Preview** (`code_block_overflow_x_scroll`): keep the raster at intrinsic size and enable `overflow_x_scroll` (with `restrict_scroll_to_axis`) so wide diagrams stay readable and can be panned horizontally. - **Compact UIs** (e.g. agent): keep previous `max_w_full()` fit-to-pane behavior. Fixes #61051 ## Test plan - [ ] Open a markdown file with a wide ` ```mermaid ` flowchart (e.g. multi-column TB graph) in Markdown Preview - [ ] Confirm diagram is not crushed to pane width; text remains legible at default scale - [ ] Confirm horizontal scroll/pan works on the diagram without stealing vertical page scroll - [ ] Confirm compact surfaces that leave `code_block_overflow_x_scroll` off still fit diagrams to width - [ ] Confirm mermaid scale fence info still works (` ```mermaid 150 `) - [ ] Confirm Preview/Code tabs and copy button still work --- Release Notes: - Fixed wide Mermaid diagrams in Markdown Preview being squashed and illegible |
||
|
|
9f1883fd4a |
editor: Fix crash when copying and pasting using multiple cursors (#61545)
Fixes a crash when copying and pasting a mixed empty/nonempty multi-cursor selection. `Editor::do_copy` is meant to insert a newline after each non-final selection that doesn't copy the entire line, but `prev_selection_was_entire_line` is currently based on the current selection instead of the previous one. `Editor::cut_common` does already correctly track this state across loop iterations. This can lead to an out of bounds crash when pasting because the indexing logic in `Editor::do_paste` relies on these newlines being added correctly, depending on `is_entire_line`. Repro: ``` foo bar ``` 1. select `foo` 2. option-click after `bar` to add an empty selection ``` «fooˇ» barˇ ``` 3. copy 4. paste ## 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 crash when copying and pasting using multiple cursors. |
||
|
|
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> |
||
|
|
414e6fe31e |
client: Extract proxy handshakes into a new proxy_handshake crate (#61427)
This consolidates the proxy code in `client/src/proxy` into a new `proxy_handshake` crate that implements the client side of HTTP CONNECT and SOCKS4/4a/5/5h handshakes sans-IO: the protocol logic is a pure state machine that never touches a socket, with thin drivers behind `futures-io` and `tokio` feature flags. `client` now drives the websocket's proxy tunnel through the tokio driver, and the `tokio-socks` dependency goes away. The main win is testability: the handshakes are now covered by synchronous byte-level tests on both sides of each exchange, plus a property test that the outcome is invariant under how the proxy's bytes are chunked across reads — the class of partial-read bug that's hard to hit with hand-written tests but easy to hit in production behind a buffering proxy. The crate is written as if it were standalone (no zed-internal dependencies, structured errors instead of `anyhow`), which is also why it grows both driver flavors rather than just the one `client` needs today. Two deliberate behavior changes, both converging on spec/curl semantics: - Proxy credentials embedded in URLs are now percent-decoded before use, per RFC 3986 §3.2.1. Previously they were sent in their encoded form, which only worked for credentials with no reserved characters. A password that literally contains something like `%40` and relied on the old behavior now needs the RFC-correct `%2540` spelling. - `NO_PROXY` is now honored for the collaboration connection, matching the exclusions reqwest already applies to the rest of Zed's HTTP traffic. TLS to the proxy itself (for `https://` proxy URLs) and DNS policy stay in `client`, since those are I/O concerns the sans-IO crate deliberately doesn't own. Release Notes: - Improved proxy support: the collaboration connection now respects `NO_PROXY` and percent-encoded proxy credentials. |
||
|
|
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 |
||
|
|
3c9a3d4176 |
editor: Preserve preview tabs for references multibuffers (#61021)
When `preview_tabs.enabled` and `preview_tabs.enable_preview_multibuffer_from_code_navigation` are enabled, Find All References opens its multibuffer as a preview tab. A references multibuffer is assembled from existing buffers, which may already contain edits when the preview is created. When creating the multibuffer to display the references, it ends up emitting edit events as excerpts are added, this will later cause `Pane::handle_item_edit` to run, which would see these buffer edits since `Buffer::preview_version` and unpreview the tab, as the `Buffer::preview_version` value was not being updated after edits. Refresh the multibuffer’s preview baseline before opening a newly created code-navigation multibuffer as a preview. Background diff updates then preserve the preview, while subsequent user edits still make it permanent. This leaves the existing editor event and search invalidation behavior unchanged. Release Notes: - Fixed `editor: find all references` preview tabs becoming permanent tabs if any of the buffers had been edited before --------- Co-authored-by: dino <dinojoaocosta@gmail.com> |
||
|
|
3a547a44df |
bedrock: Fix duplicated messages and colliding tool call ids from Bedrock Mantle (#60998)
## Problem AWS Bedrock's Mantle endpoint (used for GPT-5.x models via the OpenAI-compatible Responses API) has two independent bugs that both cause visible duplication/corruption in the agent panel: 1. **Duplicated message text.** Mantle streams a reply as a series of new `message` output items, where each new item's text is a growing prefix-superset of the previous one, and the full `output_text.delta` sequence is replayed for each item. Forwarding these events through the shared `OpenAiResponseEventMapper` unmodified caused the assistant's reply (and its phase/reasoning metadata) to appear duplicated in the UI. 2. **Colliding tool call ids.** Mantle assigns raw `tool_use` ids as a simple per-request counter (`call_1`, `call_2`, ...) that resets to `call_1` on every request/response cycle to the model — including separate cycles within a single agent turn as it performs tool calls sequentially. Since `acp::ToolCallId` was built directly from that raw id, and `AcpThread::upsert_tool_call` matches tool calls by id across a thread's entire entry list, a later, unrelated tool call reusing a raw id would silently overwrite an earlier, already-completed one instead of appearing as a new entry — visible as "old tool calls getting replaced by new ones." Both were confirmed against real raw Mantle SSE traces and a real persisted thread (`call_1` recurring across 10+ separate request cycles within a single turn). ## Fix **For message duplication:** `MantleResponseEventMapper` wraps `OpenAiResponseEventMapper` and collapses adjacent, same-phase, strict-prefix message extensions into a single logical message, forwarding only the replayed suffix as ordinary incremental text. - Only adjacent, same-phase, strict-prefix extensions are collapsed. Equal, shrinking, divergent, or different-phase messages are still shown as-is. - Any non-message output item (reasoning, tool call) is a hard boundary: it's forwarded unchanged and clears the merge state, so a message after a tool call is never merged with the one before it. - When a message is merged into the previous one, its `StartMessage` and `ReasoningDetails` metadata events are suppressed, since they'd otherwise duplicate what was already emitted for the first message. **For tool call id collisions:** `scoped_tool_call_id(message_ix, tool_use_id)` combines the raw provider id with the index of the `AgentMessage` it belongs to in `Thread::messages`. That index is stable for the lifetime of one request/response cycle (`flush_pending_message` only runs on the next `StartMessage` event), so ids stay unique across the whole thread without needing the raw provider id itself to be globally unique. The index is threaded through explicitly from where each tool call is created (`handle_tool_use_event`/`run_tool`) to where it's later referenced (`process_tool_result`), rather than recomputed later by re-reading `Thread::messages.len()`. We deliberately did not rewrite the raw `tool_use` id itself at the provider layer to make it globally unique, since that id round-trips back to Mantle verbatim as `call_id` in `function_call_output` items on the next request — rewriting it would require a fragile reverse-mapping on every code path that replays tool results. ## Testing - `cargo test -p language_models --lib bedrock` — 23/23 pass (11 tests covering coalescing, independent messages, phase boundaries, tool/reasoning boundaries, chained cumulative extensions, and metadata deduplication). - `cargo test -p agent --lib` — 699/699 pass (2 new regression tests for tool call id scoping: one via live streaming across two request cycles in one turn, one via persistence/`Thread::replay()` across two separate turns). - `script/clippy -p language_models -p agent` — clean. Release Notes: - Fixed duplicated assistant replies and colliding tool calls when using GPT-5.x models on Amazon Bedrock's Mantle endpoint |
||
|
|
d5f26118c5 |
agent: Fix edit_file failing to match exact mid-line old_text fragments (#61489)
Fixes the `edit_file` tool failing to resolve `old_text` fragments that only cover part of a longer line. The streaming matcher compared the query against whole trimmed buffer lines, so an exact substring like `keyboard WASD, voxel-based` inside a much longer line failed the fuzzy similarity threshold and the edit was rejected with "did not match any content". Supersedes #60615 — thanks to @ziimakc for the report, reproduction, and initial investigation there. This PR takes a different approach based on review feedback on that PR. ## Approach - `StreamingFuzzyMatcher::push()` is unchanged: it still fuzzy-matches completed lines incrementally so the UI can reveal the likely edit location while `old_text` streams in. - `finish()` now first searches the buffer for the complete raw query as an exact byte substring (rope-native, overlap-aware KMP; no copy of the buffer). Exact matches take precedence; fuzzy matching remains the fallback for indentation drift, typos, and inserted/omitted lines. - Exact matches are capped at two occurrences — enough to prove ambiguity — and ambiguous or overlapping matches are rejected with the existing "matched multiple locations" error instead of silently editing one. - The matcher now returns match candidates with their line alignment and exact/fuzzy provenance in one result, and the edit pipeline uses that to reindent correctly: for an exact mid-line match the first replacement line keeps the retained prefix (zero delta) while subsequent lines get the contextual indentation. - The streaming parser now preserves the trailing newline of finalized `old_text` (it still strips it from `new_text` to avoid duplicate line endings, per #52661), so `"foo\n"` can disambiguate a standalone `foo` line from `foo suffix`. ## Notes - Exact-search cost is O(buffer + query) at finalization only; the buffer is never copied into a `String` (the main concern with the original PR). - New regression tests cover mid-line fragments, exact-over-fuzzy precedence, overlapping-match ambiguity, multiline replacement indentation (spaces and tabs), trailing-newline disambiguation, and newline-only edits. Closes https://github.com/zed-industries/zed/issues/59369 Release Notes: - Fixed agent edits failing when the text to replace is only part of a line |
||
|
|
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. |
||
|
|
5ece0b3aaa |
CONTRIBUTING.md: Document the cap on simultaneous PRs (#61516)
We are trying out the new feature that GitHub rolled out, will see if it is helpful. Release Notes: - N/A |
||
|
|
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> |
||
|
|
711ade2324 |
Fix permission for pull request labelling script (#61525)
While its the `issues` API we use for labelling, it seems that GitHub still wants PR permissions for those. Hence, fixing here. Release Notes: - N/A |
||
|
|
c0af112ad5 |
search: Fix expand/collapse button for non multibuffer items (#61519)
# Objective Fix an issue where the button was being shown in the LSP log view even because it's `Item::buffer_kind` implementation was returning the default `ItemBufferKind::None` value. ## Solution Update the `BufferSearchBar::needs_expand_collapse_option` implementation to return `false` for all non-multibuffer items instead of only returning false for singletons. ## Testing Tested both manually as well as added a new test for this change – `search::buffer_search::tests::test_no_expand_collapse_option_when_item_is_not_buffer_backed`. ## 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 ## Showcase <details> <summary>Before</summary> <img width="3824" height="2482" alt="CleanShot 2026-07-23 at 11 18 37@2x" src="https://github.com/user-attachments/assets/f435ca07-5eb0-4c16-b567-ea066dbc0ccd" /> </details> <details> <summary>After</summary> <img width="3776" height="2482" alt="CleanShot 2026-07-23 at 11 19 53@2x" src="https://github.com/user-attachments/assets/b94e59cf-8888-470f-acd1-3bb1b714e62d" /> </details> --- Release Notes: - Fixed issue where "Collapse All Files"/"Expand All Files" button was being shown in LSP Log View |
||
|
|
336679c8e1 |
Fall back to file names in breadcumbs with LSP symbols (#61511)
Closes https://github.com/zed-industries/zed/issues/60905 Also makes the breadcrumbs to update on settings change — before, one needed to focus them. Release Notes: - Improved breadcrumbs for `"document_symbols": "on"` case when no LSP data is sent |
||
|
|
146a568c79 |
ci: Configure more steps more explicitly (#61401)
Also adds some Zizmor validations. Release Notes: - N/A |
||
|
|
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> |
||
|
|
97b51f2620 |
language: Fix JSON rainbow bracket colors across chunks (#60741)
## Context
JSON rainbow bracket colors could shift across row chunk boundaries when
large ancestor objects were omitted by the bounded tree-sitter bracket
query window. This fixes the chunk-local depth reset by caching bracket
chunk data together with the active bracket stack after each chunk, then
using that inherited stack when later chunks are computed. For JSON
object braces that are too large for the bounded query, the
implementation recovers active ancestor `{...}` pairs from the syntax
tree so sibling object braces keep the same color even when jumping
directly to a later chunk.
Closes #50185
## How to Review
`crates/language/src/buffer/row_chunk.rs` adds indexed access to row
chunks so bracket cache computation can walk from the nearest cached
chunk up to the requested chunk.
`crates/language/src/buffer.rs` changes bracket range caching from
storing only per-chunk matches to storing per-chunk matches plus the
active bracket stack after that chunk. It preserves the existing bounded
query and greedy-match repair behavior, while adding JSON-specific
ancestor recovery for large object braces omitted by
`MAX_BYTES_TO_QUERY`.
`crates/language/src/buffer_tests.rs` adds a JSON regression fixture
that exceeds `MAX_BYTES_TO_QUERY`, fetches a later chunk before earlier
chunks, and verifies all same-depth sibling object braces keep the same
`color_index` across row chunks.
Video of manual test below :
[Screencast from 2026-07-10
08-09-30.webm](https://github.com/user-attachments/assets/fca6425b-b79c-4097-b4af-148db6aa23d9)
## 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 JSON rainbow bracket colors changing across row chunk
boundaries.
---------
Co-authored-by: Kirill Bulatov <kirill@zed.dev>
|
||
|
|
6c4b9ae965 |
Replace panicking unwraps in iterator and Option chains (#61277)
# Objective Remove `.unwrap()` calls in iterator/`Option` chains that could panic at runtime. ## Solution Use `and_then`/`filter_map` with `.ok()` for fallible downcasts (`entry_view_state.rs`) and keystroke parsing (`vim/command.rs`); use a descriptive `expect` in `suggest_autoindents` where the invariant is intentional (`buffer.rs`). ## Testing - `cargo test -p language buffer` (69 passed) - `cargo test -p vim command` (26 passed) - `cargo test -p agent_ui entry_view` (3 passed) ## Self-Review Checklist: - [x] I have reviewed my own diff for quality, security, and reliability - [ ] Unsafe blocks (if any) have justifying comments - [ ] The content adheres to Zed's UI standards - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable Release Notes: - N/A |
||
|
|
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> |
||
|
|
cfeafdd22a |
Fix incorrect array merging in LSP initialization_options (#54950)
In lsp_store, user's lsp initialization_options are merged into the adapter's defaults using `merge_json_value_into`; this merges by concatenating arrays, which can produce duplicate entries. Adds merge_json_value_into_replacing_arrays, a variant that replaces arrays instead of merging; uses it for LSP initialization options. `merge_json_value_into` is kept since some callers intentionally use array concatenation (extending rust-analyzer's experimental.commands.commands list). Closes #54892 Release Notes: - Fixed duplicated or extra array values in LSP `initialization_options` when user settings override LSP defaults with an array --------- Co-authored-by: Kirill Bulatov <kirill@zed.dev> |