ecac6c00a63a4be5ee22a110425b6e4834a3486c
39284
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
ecac6c00a6 |
Fix zoomed panels closing when focus moves within the panel (#59439)
Closes FR-139 Most focus-lost issues that close the agent panel in Zen mode stem from panels returning a transient child editor's focus handle from `Focusable::focus_handle`. The Zen-mode check closes the zoomed panel when the focused element is not a descendant of the panel's focus handle, so any focus movement inside the panel that landed outside that child editor looked like the panel losing focus. This PR separates the two roles that handle was serving: - `Focusable::focus_handle` now always returns a stable handle tracked at the panel's root element, used for containment checks (Zen-mode auto-close, `toggle_panel_focus`, dock focus subscriptions). - The new `Panel::activation_focus_handle` returns what should receive focus when the panel is activated (e.g. a filter/commit/message editor) and must be a focus-tree descendant of the root handle. All "focus the panel" callsites in workspace/dock now use it. Migrated panels: `AgentPanel` (including thread views and the toolbar title editor), `CollabPanel`, `GitPanel`, `OutlinePanel`, and `TerminalPanel` (previously delegated to the active pane, so focus in a non-active pane dropped containment). `CollabPanel` activation falls back to the panel root when signed out or collaboration is disabled, since the filter editor isn't rendered in those states. Also fixes duplicate element ids for tool calls with multiple content blocks. Tests: a regression test that clicks tool-call output and focuses the thread title editor while zoomed (both previously closed Zen mode), and a dock-level test asserting the activation handle receives focus on panel activation while the panel root reports containment. Release Notes: - Fixed zoomed panels (e.g. the agent panel in Zen mode) closing unexpectedly when focus moved to elements inside the panel, such as tool call output or the thread title editor. |
||
|
|
1c2a643cde |
Fix Bedrock effort and regional routing (#61597)
Fixes Amazon Bedrock adaptive-thinking requests so the selected effort reaches Anthropic models, and routes Claude Opus 4.7 and 4.8 through their documented Japanese and Canadian inference profiles. Release Notes: - Fixed Amazon Bedrock effort selection and regional routing for Claude Opus 4.7 and 4.8. |
||
|
|
1c244c194b |
git_panel: Use specific label and prompt for reverting deleted file (#61554)
# Objective I expected a different label for reverting a file deletion like Zed already has for reverting a file creation. ## Solution This PR implements a new label and prompt. VS Code also shows a different prompt while keeping the label static but I think it makes more sense to let both adapt. ## Testing Just deleted a file and checked menu label and prompt. ## Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [ ] Unsafe blocks (if any) have justifying comments - [x] The content adheres to Zed's UI standards ([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) and [icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md) guidelines) - [ ] Tests cover the new/changed behavior - [ ] Performance impact has been considered and is acceptable ## Showcase <img width="363" height="139" alt="image" src="https://github.com/user-attachments/assets/6be7e5b9-7250-449e-9cba-ea5a2099dd3a" /> <img width="349" height="240" alt="image" src="https://github.com/user-attachments/assets/d87d5b4b-ff29-4976-8078-314c94a71896" /> --- Release Notes: - Git Panel: Added specific label and prompt to context menu for reverting a deleted file |
||
|
|
777b94dfb4 |
search: Preserve cleared query when reopening the text finder (#61585)
## Context Closes #61394 The Text Finder persists the last query per workspace (in the `text_finder_queries` table) so it can seed itself on reopen. Persistence happens in `TextFinder::on_before_dismiss`, but it was guarded by `if !query.is_empty()`, so clearing the query and dismissing never wrote anything. The stale non-empty query stayed in the database and got restored on the next open, making it impossible to "clear and keep it cleared." This removes the guard so dismissal always persists the current query, including an empty one. The read side already treats an empty stored query as "nothing to restore" (`load_last_search` returns `None` for an empty string), so an empty write cleanly clears the seed instead of leaving the previous query behind. Manual test below : [Screencast from 2026-07-24 15-24-33.webm](https://github.com/user-attachments/assets/ba305f54-8ec2-4d3d-be0b-e2eb001bb204) ## How to Review **`crates/search/src/text_finder.rs`** `on_before_dismiss` no longer gates the write on a non-empty query. It always calls `store_last_search` with the picker's current query and options. `store_last_search` still early-returns for workspaces without a `database_id`, so unpersisted workspaces are unaffected, and `load_last_search` still maps an empty persisted query to `None`, so `seed_query` won't resurrect it. The active-item selection still takes priority over the persisted value on reopen, so seeding from a live editor selection is unchanged. The tests' shared `init_test` now installs a test `db::AppDatabase` global. This is required because the new test is the first one to actually reach `TextFinderDb::global(cx)`. The existing `test_dismiss_from_within_workspace_update` leaves the workspace's `database_id` as `None`, so it short-circuits before touching the DB. `test_clearing_query_does_not_restore_previous_query` exercises the real persistence path: it assigns a workspace `database_id` (`set_random_database_id` + `flush_serialization`), opens the finder with a query, dismisses, and asserts the query round-trips through `seed_query`; then it reopens, clears the query via `set_query("")`, dismisses, and asserts `seed_query` is now `None`. The positive round-trip assertion keeps the negative case from passing vacuously. ## 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 the project search / Text Finder restoring a previous query after it had been cleared and dismissed |
||
|
|
aefad70496 |
Revert force hardmark settings for documentation hover (#61622)
Closes https://github.com/zed-industries/zed/issues/60777 # Objective - Due to #59426, forcing docString softmark to hardmark, an regression has appeared. It causes all docString on different language to load newLine (`\n`) by default, instead of soft wrap. - By checking the issue, turns out we should not setting `soft_break_as_hard_break: true`, this will make the hover docString less - Details can refer to #60777 ## Solution - Revert settings by removing the line in `hover_popover.rs:742` ## Testing - About the testing result and comparsion, you can refer to #60777 - Updated test `test_hover_markdown_preserves_soft_breaks` to `test_hover_markdown_soft_breaks_reflow_per_commonmark` ## 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 an issue where hover documentation could have too many line breaks. --------- Co-authored-by: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com> |
||
|
|
04e53be020 |
git_ui: Ensure discarding tracked changes respects staging state (#61608)
Closes #56020 Release Notes: - Fixed Discard Tracked Changes discarding unstaged files --------- Co-authored-by: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com> |
||
|
|
db7d5ddd19 |
Skip [DONE] stream terminator in anthropic and google_ai SSE parsers (#61627)
## Problem
When `api_url` points to a proxy or gateway that appends `data: [DONE]`
to the SSE stream, every streaming completion fails with:
```
error deserializing Anthropic API response: expected value at line 1 column 2
```
In the UI this surfaces as **"error deserializing Anthropic API response
— Retrying (Attempt 3 of 3)"** followed by **"Connection Interrupted"**,
even though the proxy returned a well-formed stream and the model's full
response was already delivered before the terminator. The failure is
100% reproducible on multi-turn tool-use conversations (Zed reads the
stream to completion after each turn, so it always reaches the trailing
`[DONE]`) and intermittent on single-turn conversations (depending on
whether the connection closes before the line is read). The same class
of error appears in the `google_ai` crate as `Error parsing JSON: ...
"[DONE]"`.
Neither side is at fault here. Zed's current parser is a correct
implementation of the Anthropic and Gemini specs, which terminate
streams by connection close and never emit `[DONE]`; at the same time,
appending a `[DONE]` terminator is a common, legitimate convention among
SSE gateways. This PR is a compatibility improvement that makes Zed
robust to that widely-used stream shape, so streaming works whether or
not the upstream emits the terminator.
## Why Zed crashes but the Anthropic SDK does not
The Anthropic TypeScript and Python SDKs handle this correctly
**without** any explicit `[DONE]` check. Their SSE parser uses a
two-layer architecture:
1. **SSE framing layer** — parses `event:` / `data:` fields into
`{event, data}` objects without inspecting the data payload.
2. **Event dispatch layer** — only calls `JSON.parse` on events whose
`event` name is in a known whitelist (`message_start`,
`content_block_delta`, etc.). A bare `data:` line with no preceding
`event:` line yields `event: null`, which is not in the whitelist and is
silently ignored.
So when a proxy sends `data: [DONE]`, the SDK produces `{event: null,
data: "[DONE]"}`, the dispatch layer drops it, and `JSON.parse` is never
run on `[DONE]`. Claude Code and Cline both use the Anthropic SDK under
the hood, so they inherit this behavior and never crash on `[DONE]`.
Zed's `anthropic` and `google_ai` crates use a simpler single-layer
parser: strip the `data:` prefix, then unconditionally
`serde_json::from_str` the remainder. There is no event-name dispatch,
so `[DONE]` goes straight into the JSON parser — `[` looks like an array
start, `D` is not a valid value, serde reports `expected value at line 1
column 2`, and the stream dies.
## Fix
Add a one-line guard after prefix stripping: if the trimmed payload is
`[DONE]`, return `None` from the `filter_map` closure. This is a
lightweight equivalent of the SDK's whitelist-ignore behavior — same
result (silently skip the terminator), without restructuring the parser
into a full event-name dispatch architecture.
Two commits, one per crate:
1. `anthropic` — guard in `stream_completion_with_rate_limit_info`
2. `google_ai` — identical guard in `stream_generate_content`
## Scope
The other ten SSE-based providers in this repo (`open_ai`, `deepseek`,
`mistral`, `open_router`, `lmstudio`, `llama_cpp`, `copilot_chat`)
already handle `[DONE]` because their upstream specs (OpenAI-compatible)
define it as a required stream terminator. `ollama` (NDJSON) and
`bedrock` (AWS SDK event stream) do not use SSE. After this PR, every
SSE parser in Zed handles `[DONE]` without error.
## Safety
- Official Anthropic and Gemini APIs never send `[DONE]`; the guard is a
no-op on direct connections.
- `line.trim() == "[DONE]"` handles both `data: [DONE]` and
`data:[DONE]`.
- Returning `None` drops the line silently; the stream concludes on the
next EOF as usual.
Release Notes:
- Fixed streaming completions failing with "error deserializing
Anthropic API response" when the SSE endpoint appends a `[DONE]` stream
terminator (affects custom `api_url` proxies for Anthropic and Google
Gemini)
|
||
|
|
9ec4826944 |
agent: Improve error messaging for edit_file tool (#61662)
# Objective Currently, when a model provides the wrong parameters to the edit file tool, it gets back the opaque error message `data did not match any variant of untagged enum ValueOrJsonString`. At least some models (DeepSeek in my experience) can't figure out what to do from this point, and keep trying the same wrong parameter names in the tool call before eventually falling back to using `ed`. This may address https://github.com/zed-industries/zed/issues/58622. ## Solution Rather than attempting to deserialize to the `ValueOrJsonString` enum, try to deserialize as a JSON string and then as a value in turn, so that deserialization errors better propagate. ## Testing Using DeepSeek V4 Pro. Tried it out in a reloaded conversation where the edit tool was consistently failing. Asked it to stress-test the edit tool. Only one edit failed after a few successful attempts, and returned the error message "missing field `new_text`". Subsequent edits worked again rather than resulting in a doom loop. I don't think the model noticed what happened, but it seemed to help. <img width="366" height="551" alt="image" src="https://github.com/user-attachments/assets/6f9c0c8d-bf94-4670-bad0-0ead5c1fff4e" /> ... <img width="346" height="153" alt="image" src="https://github.com/user-attachments/assets/2afa2901-9a90-4142-aa9d-ff32a7be0d0c" /> --- Release Notes: - Improved edit_file tool error messaging. --------- Co-authored-by: MrSubidubi <finn@zed.dev> |
||
|
|
cecc753582 |
acp: Validate and surface more elicitation warnings (#61708)
Eventually more of this should move into the SDK I think, but makes several states with forms and urls clearer to the user. Release Notes: - N/A |
||
|
|
b38f75dcce |
Add agent panel font family settings (#59629)
Objective: Allow users to configure the font families used by agent panel content separately from the main UI and buffer fonts. Solution: - Add `agent_ui_font_family` for agent responses in the agent panel. - Add `agent_buffer_font_family` for the agent panel message editor and user messages. - Keep context menus on the primary UI font family. - Document the new settings and expose them in the settings UI. Testing: - Ran `cargo fmt`. - Ran `cargo check -p settings_content -p theme_settings -p markdown -p agent_ui -p settings_ui -p ui`. - Ran `git diff --check`. - Manually tested the agent panel font behavior in a dev build. Release Notes: - Added settings for configuring agent panel UI and buffer font families. Co-authored-by: Finn Evers <finn@zed.dev> |
||
|
|
34eac8ff92 |
ci: Grant version bump token more permissions (#61709)
This should hopefully fix the issue with the version bumps we were seeing - to bypass push protections, the token seems to need workflow permissions for some reason as well. Release Notes: - N/A |
||
|
|
d9e2550e28 |
gpui: Make HSLA functions const (#61682)
# Objective Make hsla functions `const`. ## Solution Made Hsla-related functions `const fn`. ## Testing > Did you test these changes? If so, how? Ran `cargo test -p gpui color` to verify the color-related tests pass. > Are there any parts that need more testing? No additional testing is required since this change only changes existing color functions to `const fn`. > How can other people (reviewers) test your changes? Is there anything specific they need to know? Reviewers can run `cargo test -p gpui color` to verify the changes. > If relevant, what platforms did you test these changes on, and are there any important ones you can't test? Tested on macOS. No platform-specific behavior is 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 --- Release Notes: - N/A |
||
|
|
d6f9136ca8 |
Fix typo in .rules (#61693)
## Objective A phrase in `.rules` was missing a verb. ## Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content adheres to Zed's UI standards ([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) and [icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md) guidelines) - [ ] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable --- Release Notes: - N/A |
||
|
|
134275b0ae |
Avoid unnecessary git scan when the agent creates a checkpoint (#61271)
Agent checkpointing is implemented by staging selected files to a temporary git index file, then creating a commit. To avoid checkpointing commonly-excluded files even when the user doesn't have them in their gitignore, we write a temporary override to .git/info/exclude while running the staging. However, this causes us to do an unnecessary git scan when a checkpoint happens, because in general we want to do this when `.git/info/exclude` changes (the user might have edited it). This PR fixes that by doing the staging in two steps: - First, we stage any tracked files - Then we get a list of untracked files to include and stage those explicitly. The list is obtained by running `git ls-files` with a custom ignore file in addition to the `--standard` ignores; we write that custom ignore file to a path ending in `tmp` under .git, which means that our worktree code will not start a git scan in response to its events (the same way it already works for the temporary index file). .git/info/exclude is never touched. Note that we already listed all untracked files before this PR, in order to exclude the large ones. Release Notes: - Fixed Zed doing unnecessary work when the agent created a checkpoint. |
||
|
|
ef0b6f158d |
fs: Fix crash loop from closedir panic during worktree scan (#59953)
# Objective Fixes #59952. Zed crash-loops on launch. The faulting thread aborts inside the Rust standard library while closing a directory handle during background worktree scanning: `std`'s `DirStream::drop` (`library/std/src/sys/fs/unix.rs`) `assert!`s that `closedir()` succeeds unless the error is `EINTR`. That handle originates in `RealFs::read_dir`, which wraps `std::fs::read_dir(path)` in `stream::iter(...)` and carries the live `ReadDir` across async boundaries; the worktree `BackgroundScanner` (`scan_dir` → `forcibly_load_paths`) later drops the stream. If `closedir()` returns a non-`EINTR` error (e.g. `EBADF` under file-descriptor pressure — seen alongside repeated `unable to start FSEvent stream` warnings on a large dependency tree), `std` panics inside `Drop`. Zed's `crashes::panic_hook` turns any panic into `process::abort()`, and because the same workspace is re-scanned every launch, this is a permanent crash loop. (`catch_unwind` can't help: the hook aborts before unwinding.) ## Solution Stop relying on `std`'s asserting close. Add a `read_dir_entries(path)` helper that reads entries eagerly so the directory handle is opened and closed within a single call: - On unix, read via libc (`opendir`/`readdir`/`closedir`) and **deliberately ignore a failing `closedir`**, so a close error degrades gracefully instead of aborting the process. - On non-unix, keep `std::fs::read_dir` (which has no such assert) but collect eagerly so the handle is dropped within the call. `RealFs::read_dir` now calls this helper. The change is scoped to `crates/fs/src/fs.rs`; the watcher, scanner, and panic hook are untouched. ## Testing - Added unit tests in `crates/fs/src/fs.rs` for `read_dir_entries`: entry listing, `.`/`..` exclusion, empty directories, and the missing-directory error path. - `cargo test -p fs read_dir` → 3 passed. - `RUSTFLAGS="-D warnings" cargo build -p fs`, `cargo clippy -p fs --all-features --all-targets -- -D warnings`, and `cargo fmt -p fs --check` are all clean. - Tested on macOS (aarch64). The `fs` crate compiles within the full `cargo build -p zed` graph. I could not produce a running app binary in my environment (the `gpui_macos` Metal step needs full Xcode, not just Command Line Tools) — reviewers on a full Xcode setup can `cargo run -p zed`. - The original `closedir` `EBADF` is not deterministically reproducible, so the fix is structural rather than verified against a live repro; the tests guard the read path and behavior. ## Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content adheres to Zed's UI standards — N/A (no UI change) - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable --- Release Notes: - Fixed Zed crash-looping on launch when `closedir` fails during background directory scanning ([#59952](https://github.com/zed-industries/zed/issues/59952)). --------- Co-authored-by: Cole Miller <cole@zed.dev> |
||
|
|
b73d91382d |
workspace: Retain panes while saving (#61683)
Save tasks can suspend while waiting for prompts, formatting, or filesystem I/O. Holding only a WeakEntity<Pane> allowed the pane to be released during those suspension points, surfacing an internal 'entity released' error as a failed save. Instead upgrade the pane once the save operation starts so we can ensure it finishes. --- Release Notes: - N/A or Added/Fixed/Improved ... |
||
|
|
70ae02b99e |
Fall back to path-only mention for binary files in the agent panel (#61279)
## Summary - Dragging a binary file (docx, xlsx, pdf, etc.) into the agent panel's message editor inserted a mention link, then asynchronously tried to load its content as a text buffer. That failed with "Binary files are not supported", which surfaced an error toast **and** deleted the mention text that had already been inserted. - `confirm_mention_for_file` now catches that specific failure and falls back to `Mention::Link` (a path-only reference, same as directory mentions already use), instead of failing the whole mention and reverting the edit. ## Test plan - [ ] Drag a `.docx` or `.xlsx` file into the agent panel chat input — the file path mention should stay inserted with no error toast. - [ ] Drag a regular text file in — content mention still works as before (unaffected code path). Release Notes: - Fixed dragging a binary file (docx, xlsx, pdf, etc.) into the agent panel deleting the inserted reference and showing a "Binary files are not supported" error --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Cole Miller <cole@zed.dev> |
||
|
|
55b2687062 |
editor: Check anchor validity for hovered links (#61686)
Closes FR-112 Otherwise, if a multibuffer snapshot changed under the hood for example one of the paths changed, without doing an explicit validity check, we would panic during comparison instead. Release Notes: - Fixed panic when hovering links during an under-the-hood multibuffer changes. |
||
|
|
19d5ca984a |
gpui_wgpu: Fix bidi paragraph shaping crash (#61651)
Closes FR-133 `cosmic-text`'s BiDi line shaping machinery (`ShapeLine::new`) asserts that every BiDi paragraph is following the same direction. It turns out that our `gpui_wgpu` line shaping adapter would not account for that leading to panics if text contained multiple BiDi paragraphs with multiple directions. Not super common but worth fixing as the fix is not super complicated. At the same time, I'd like to point out that there is a patch submitted to `cosmic-text` that redoes shaping logic so that this is no longer illegal: https://github.com/pop-os/cosmic-text/pull/508 If it gets accepted, we can revert this fix. Release Notes: - Fixed panic in `gpui_wgpu` if text contained multiple BiDi paragraphs with mismatched directions. |
||
|
|
efc3ba73b5 |
csv_preview: Refine filter popover UI (#61138)
# Objective
- The column filter popover was a static `ContextMenu`: no search, and
it didn't scale to columns with many unique values.
## Solution
- Replaced it with a `Picker<ColumnFilterDelegate>` with fuzzy search
and match highlighting over the column's unique values.
- Row order is frozen at open time (available first, then values hidden
by other filters under a "Hidden by other filters" header) so toggling a
value doesn't reshuffle the list.
- Added a footer with `{selected} / {total} rows selected` and "Clear
all".
- Added `fuzzy` and `picker` deps to `csv_preview`.
## Testing
- Search narrows to fuzzy matches with highlighting.
- Toggling a value updates its checkmark and footer count without
closing or reordering the list.
- Values excluded by another column's filter show disabled under "Hidden
by other filters".
- "Clear all" clears the column's filters and keeps the popover open.
## Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [ ] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [ ] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
## Showcase
| Before | After |
| --- | --- |
| <img width="660" height="351" alt="image"
src="https://github.com/user-attachments/assets/c78084a2-d327-4d48-9c05-f35383455713"
/> | <img width="660" height="354" alt="image"
src="https://github.com/user-attachments/assets/910d52ef-4530-4ac7-91ac-3db318cf6c19"
/> |
**+ search**
<img width="972" height="574" alt="image"
src="https://github.com/user-attachments/assets/1a26d0fc-c96c-4973-818d-7d053e8cce73"
/>
---
Release Notes:
- N/A
|
||
|
|
0fd17feb17 |
gpui: Fix dropped frames when scrolling an unfocused window (#61600)
Scroll events are delivered to the window under the pointer even when it isn't focused, but we cap inactive windows at ~30fps to save energy, so scrolling an unfocused window visibly drops frames. We now exempt high-rate input from the cap using the existing `InputRateTracker`: a trackpad scroll stream lifts it while events are arriving and for one second after the last burst, then the cap resumes on its own. ## 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 dropped frames when scrolling unfocused windows. |
||
|
|
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> |