## Summary
Advance wgpu from `3b3506e` to `cddb2f5` to adopt gfx-rs/wgpu#10348
(reported in gfx-rs/wgpu#10341). Keep the shader-validation Naga
dependency at the same revision. The lockfile changes only the sources
of the 13 wgpu-family packages; package versions and other dependency
selections are unchanged.
WebGL fence waits use a zero timeout because browsers do not support an
indefinite client wait. A fence can therefore legitimately time out
while GPU work is pending. The old surface reconfiguration path treats
that timeout as unreachable and traps; the upstream fix handles it
without weakening the native teardown behavior. This revision also
retains the Vulkan teardown fix that required the existing Git
dependency.
## Verification
- `cargo test --locked -p gpui_wgpu --lib valid_wgsl`: all three shader
validation tests pass.
- `cargo tree --locked -p gpui_wgpu --target all --depth 1`: runtime
wgpu and shader-validation Naga resolve to the same revision.
- Minimal real Chromium/SwiftShader Wasm reproduction: the original
dependency traps at `wgpu-core/src/instance.rs:884` during repeated
present/reconfigure operations; the fixed dependency completes all 20
iterations.
- Downstream optimized Wasm build and Chromium WebGPU/WebGL
start-and-resize smoke tests passed using this exact Zed branch commit.
- Negative control: forcing the old wgpu dependency in the same app
makes the retained WebGL smoke test fail; the browser trace starts with
the exact `instance.rs:884:25` / `wait_indefinitely() should never
timeout` panic. Restoring the fixed dependency makes both backend cases
pass again.
## Review status
Draft only; do not land automatically. The repository-required README
review marker is intentionally left for human removal. This branch
starts at the downstream consumer's existing Zed pin, so its eventual
dependency update need not include unrelated intervening changes.
Release Notes:
- [GPUI] Fixed WebGL surface reconfiguration panics when resizing while
GPU work is pending.
---------
Co-authored-by: Tom Houlé <tom@tomhoule.com>
`TextSystem` pooled whole `LineWrapper`s, and each wrapper owns an
`Arc<TextSystem>`, so once any text was wrapped the pool kept its own
text system (and font caches) alive forever. This leaked one text system
per app for tests and embedders that create and drop apps. The pool now
keeps only each wrapper's per-font character width caches
(`CharWidthCache`), so the cache reuse is preserved without the cycle. A
regression test checks that a `TextSystem` is released after wrapping a
line and dropping all handles.
Release Notes:
- [GPUI] Fixed a memory leak where a `TextSystem` was never freed after
wrapping text, due to a reference cycle through its line wrapper pool
# Objective
On macOS, Low Power Mode reduces the CPU and GPU performance available
to applications. GPUI continued requesting animation frames at the
normal cadence, so work that no longer fit inside every refresh produced
irregular frame drops instead of a deliberate lower frame rate.
Frame throttling could also reject a display-link callback that arrived
a fraction of a millisecond before the mathematically exact target
interval. On a 120 Hz display, for example, a measured 16.666 ms
interval missed a 16.667 ms threshold and delayed the frame until
roughly 25 ms, intermittently turning a 60 fps cap into 40 fps.
## Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
---
Release Notes:
- [GPUI] Improved animation smoothness on macOS when Low Power Mode is
enabled.
---------
Co-authored-by: Anthony Eid <hello@anthonyeid.me>
## Summary
For a repo named `test_repo`, if it is bare cloned without renaming the
common dir, the common dir is `test_repo.git`, and Zed treats the
directory itself as the identity path:
https://github.com/zed-industries/zed/blob/ec86047d67acd6fddd81392f44ed6ebcc6e7f531/crates/project/src/git_store.rs#L10674-L10689
The title bar then uses the identity path to display the project name,
with the name determined by the std lib’s method:
https://github.com/zed-industries/zed/blob/ec86047d67acd6fddd81392f44ed6ebcc6e7f531/crates/title_bar/src/title_bar.rs#L284-L288
When connecting from a Unix client to a Windows remote host, the
identity path could be, for example, `C:\User\test\test_repo.git`.
Applying std’s path methods to it yields an extension of `git` and a
file stem of `C:\User\test\test_repo`, so the project name is displayed
as `C:\User\test\test_repo` instead of `test_repo`.
This PR introduces two new `PathStyle` methods to handle retrieving
`file_stem()` and `extension()` cross-platform. They mirror the std
lib’s behavior using the already introduced Path components.
## Testing
New unit tests for `PathStyle::file_stem()` and `PathStyle::extension()`
are introduced to guard its behavior. The title bar shown is locally
tested:
|Before|After|
|:--:|:--:|
| <img width="390" height="112" alt="Before"
src="https://github.com/user-attachments/assets/82c08423-a25e-4cd0-ae74-2614818d47c9"
/> |<img width="267" height="147" alt="After"
src="https://github.com/user-attachments/assets/b739c801-10ef-49da-90fb-c36233313a66"
/>|
## Self-review
- [x] I've reviewed my diff for quality, security, reliability, and
performance.
- [x] UI changes follow the
[checklist](https://zed.dev/docs/development/ui-checklist).
- [x] Tests cover the new or changed behavior.
Release Notes:
- Fixed project names in the title bar for `repo.git` bare clones on
remote Windows hosts.
When I uploaded to a remote branch with newer commits on my work the
push failed and I had no idea why until I used Git through CLI, so I
enhanced the UX so no one needs to go through this anymore.
Release Notes:
- Improved git panel treatment error, previously if you pushed from an
outdated branch, it logged a generic message and offered no solution,
now it shows an specific message with a button that allows you to solve
your issue by fetching, pulling and pushing.
Co-authored-by: Lukas Wirth <lukas@zed.dev>
## Summary
Some general reshuffling cleanups, more notable are the SubscriberSet
changes:
- Add a concrete `SingleSubscriberSet` for single-emitter observers,
removing the unnecessary outer map and emitter-key arguments.
- Keep `SubscriberSet` for observers grouped by entity or type.
- Replace separate activation and cancellation flags with one shared
`Pending | Active | Dropped` state, saving one `Rc` allocation per
subscription.
- Make `insert` immediately active and add `insert_pending` for deferred
activation, simplifying callers while preserving existing activation
timing.
- Preserve registration order and cancellation behavior when callbacks
add or drop subscriptions during dispatch. Merge retained subscriptions
with `BTreeMap::appen`d, avoiding rebuilding the tree when the
destination is empty.
Best reviewed commit by commit.
The first commit
[1740a07](https://github.com/zed-industries/zed/pull/66156/commits/1740a0718faddf57feb8cb0946a286585548ad3f)
re-orders the import / mod prelude a bit and gets rid of the lint allows
by fixing their offenses.
Release Notes:
- [GPUI] N/A
Defer the shared native window-close callback to a foreground task so
Windows destruction messages can arrive while GPUI is borrowed without
panicking or skipping cleanup. The task removes the window if still
present, then removes its system tab; a regression test delivers the
close notification while the app is borrowed and verifies cleanup after
tasks drain. Opus 5.5 review passed, and the focused test passed after
rebasing onto main (using Cargo after a Corgi Metal-toolchain failure);
the Wasm check passed before rebasing. Native Windows behavior has not
been exercised. Fixes
[FR-531](https://linear.app/zed-industries/issue/FR-531/zed-ck4-refcell-already-borrowed),
tracking [ZED-CK4](https://zed-dev.sentry.io/issues/7796580884/).
Release Notes:
- [GPUI] Fixed a panic when native window destruction re-entered GPUI
while the app was borrowed, including on Windows.
Zed reads `%s` (commit subject) from `git stash list`, but external
rename tools (lazygit, or `git stash store -m` directly) update only the
reflog message and never rewrite the underlying commit. The stash picker
therefore keeps showing the original message forever after an external
rename, even across restarts — no amount of cache invalidation or
fs-watching can fix that, because the data we ask git for genuinely
never changes.
Switch to `%gs` (reflog subject), which is what `git stash list`
displays by default and what `git stash store -m` actually updates. Also
correct an adjacent error message that claimed `git status failed` when
the failing command was `git stash list`.
Self-Review Checklist:
- [x] 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
Closes#55234.
Release Notes:
- Fixed external stash renames not being reflected in the stash picker
Co-authored-by: Finn Evers <finn@zed.dev>
This PR changes two things:
* Bumps the Tree-sitter dependency to include the grammar-loader commit
from [Tree-sitter PR
#6046](https://github.com/tree-sitter/tree-sitter/pull/6046).
- Update the extension builder to compile Zed extension grammars with an
explicit maximum size on their memory import. This makes it possible to
change the modules to work with a *shared* memory setting (needed for
multi-threaded parsing) on the Web, more efficiently. Shared memory
imports need an explicit max size, so this way we can change the import
to shared without having to move any bytes to make room for the max size
declaration.
Release Notes:
- N/A
## Summary
Closes#65718
Reproduction, Helix mode:
1. Type `abcd` in a buffer.
2. Press `x` to select the line.
3. Press `s`, enable regex, enter `\w`.
Each character is now its own selection.
4. Press `m s "`.
Result: Zed panics with `cannot seek backward` in `text.rs`.
Cause: #59201 changed `m s` to select the surrounded text together with
the new delimiters.
It uses anchors taken before the edit:
`anchor_before(start)..anchor_after(end)`.
When two selections touch, the edit inserts the closing `"` of the first
selection and the opening `"` of the second selection at the same
offset.
`anchor_after(end)` of the first selection resolves after both.
The two selections now overlap.
Resolving overlapping anchors fails the ordering check.
Fix: each edge of a new `m s` selection records anchors on both sides of
its pre-edit offset, plus the length of the text requested at that
insertion point before the edge.
After the edit, the edge moves forward by that length, but never past
the text actually inserted between its anchors.
This keeps adjacent selections apart, and keeps ranges valid when an
insertion does not land: the editor is read-only, or an excerpt ends at
the insertion point.
Requested lengths are counted per source buffer position, because
offsets on both sides of an excerpt boundary can map to the same
position, and the multi buffer coalesces their insertions.
`m r` and `m d` still use plain anchors.
## Testing
- `test_helix_surround_add_adjacent_selections` and
`test_helix_surround_add_adjacent_across_deleted_hunk` panic on `main`
without the fix.
- `test_helix_surround_add_read_only`,
`test_helix_surround_add_at_excerpt_end`, and
`test_helix_surround_add_between_excerpts` cover the cases found in
review: a selection past the buffer end, and a closing delimiter left
outside the selection.
`cargo test -p vim --lib helix::surround` and `cargo clippy -p vim
--all-targets --all-features -- --deny warnings` pass.
Manually tested on macOS with a dev build.
The reproduction above gives `"a""b""c""d"` with four selections, one
per character.
No panic.
## Self-review
- [x] I've reviewed my diff for quality, security, reliability, and
performance.
- [ ] UI changes follow the
[checklist](https://zed.dev/docs/development/ui-checklist).
- [x] Tests cover the new or changed behavior.
Release Notes:
- Fixed a crash when adding surrounding characters (`m s`) to adjacent
selections in Helix mode.
---------
Co-authored-by: Kirill Bulatov <mail4score@gmail.com>
## Summary
While looking into some performance issues with larger repositories, I
noticed that we call the method **snapshot** inside the **commit
details** & **ref label** render function, that clones the whole
snapshot even though we only need to know the branch name. So we don't
have to own/know the whole snapshot/state, so we can avoid doing this by
using the [deref reference of the repository
snapshot](https://github.com/zed-industries/zed/blob/85813709288520354d58b89e6986f05c958810b0/crates/project/src/git_store.rs#L750-L756).
## Testing
I tested that it still shows the right branch, which it should. Because
we still point to the same value, but we just skip a clone per ref label
that is inside the git graph :).
## Self-review
- [x] I've reviewed my diff for quality, security, reliability, and
performance.
- [x] UI changes follow the
[checklist](https://zed.dev/docs/development/ui-checklist).
- [x] Tests cover the new or changed behavior.
Release Notes:
- Improved Git graph rendering performance by avoiding unnecessary
repository state clones.
Co-authored-by: Kirill Bulatov <kirill@zed.dev>
Closes#56224
Follow-up to #66167.
With `focus_follows_mouse` on, right-click menus and popup pickers close
as soon as you move the mouse onto another pane. Focus jumps to that
pane, and menus close when they lose focus.
#66167 fixed this for inputs like the rename field, but not for menus.
It spotted inputs by their key context, and some menus use their own
custom key context, so there was no reliable way to spot them the same
way.
So this takes a different approach. Menus, pickers and single-line
inputs now add their focus handle to a small list in `ui` when they're
created. Focus follows mouse checks that list and doesn't move focus
while one of them is focused. This works like `ReopenablePickerRegistry`
in `modal_layer.rs`.
Approaches considered:
- Keep checking key contexts: menus with a custom key context would
still close.
- Add a flag to gpui's `FocusHandle`: works too, but gpui itself would
never use it. Focus follows mouse is a Zed feature, so gpui shouldn't
need to know about it.
Release Notes:
- Fixed right-click menus and popup pickers closing when the mouse moves
to another pane with `focus_follows_mouse` enabled.
After #65994, `corgi run` started failing on my machine with Xcode 27
because the compiled Metal shader library contained the checkout path,
which corgi rejects.
My setup:
- macOS 27.0.1 on Apple Silicon
- Xcode 27.0 (27A266a)
- corgi 0.1.83, with the repository's `corgi.toml`
The shader source is already staged in `OUT_DIR`, but Metal builds can
also embed the tools' working directories. Run both `metal` and
`metallib` from `OUT_DIR` instead of the crate directory.
A before/after check with a minimal shader on Xcode 27 confirmed that
compilation and linking succeed in both cases, and this change removes
the checkout path from the generated library. I haven't tested Xcode 26.
Release Notes:
- N/A
- [GPUI] N/A
## Summary
Fixed a bug where the title bar failed to show the Git repository,
worktree, and branch names when the opened folder was a subfolder of a
Git repository in a Windows remote project accessed from a Unix client.
The example below shows `vaspin` as the Git repository and
`vaspin/src/vaspin` as the opened folder:
|Local and Unix Remote|Windows remote before|Windows remote after|
|:--:| :--: | :--: |
|<img width="284" height="120" alt="image"
src="https://github.com/user-attachments/assets/0c499807-1399-434b-8154-a7fdcaa1087d"
/>|<img width="298" height="146" alt="image"
src="https://github.com/user-attachments/assets/0b9f716b-0ce2-4cf5-bfc0-e9d5e20f29ea"
/>|<img width="352" height="161" alt="image"
src="https://github.com/user-attachments/assets/7c7eb179-fec7-4dfd-bf6d-c288ac285e00"
/>|
## Testing
Tested locally; the comparison is shown above.
## Self-review
- [x] I've reviewed my diff for quality, security, reliability, and
performance.
- [x] UI changes follow the
[checklist](https://zed.dev/docs/development/ui-checklist).
- [ ] Tests cover the new or changed behavior.
Release Notes:
- Fixed missing Git repository, worktree, and branch names in the title
bar for Windows remote projects opened in a repository subfolder.
## Summary
Adds a `SquareR` icon to `IconName`, matching the existing `SquarePlus`,
`SquareDot`, and `SquareMinus` status badges. It's meant for marking
renamed files in diff and changes lists. The artwork is by Danilo.
No Zed code uses it yet; this only adds the icon.
## Testing
- `cargo check -p icons`
- Rendered the SVG to confirm the artwork.
## Self-review
- [x] I've reviewed my diff for quality, security, reliability, and
performance.
- [ ] UI changes follow the
[checklist](https://zed.dev/docs/development/ui-checklist).
- [ ] Tests cover the new or changed behavior.
Release Notes:
- N/A
Closes#62822Closes#63437Closes#63795Closes#59181
With `focus_follows_mouse` on, renaming or creating a file in the
project panel cancels itself as soon as the mouse rests on the panel or
a pane. Focus moves away and the rename field treats that as "done".
Terminal tab rename and a few other inline inputs have the same problem.
Now focus follows mouse leaves focus alone while a single-line editor is
focused, until you press Enter or Escape or click elsewhere.
Approaches considered:
- Skip when the hovered area already contains focus: fixes hovering the
project panel itself, but not when the context menu closes over a pane.
- Have the project panel opt out while editing: works, but every other
inline input would need the same.
- Only react to real mouse movement: still breaks as soon as you nudge
the mouse.
Release Notes:
- Fixed renaming files, creating files and renaming terminal tabs being
cancelled when `focus_follows_mouse` is enabled and the mouse moves.
Hoists the call out of the `highlights` branch so it always runs after a
seek (it’s [already internally
guarded](https://github.com/zed-industries/zed/blob/5dd9082d05/crates/language/src/buffer.rs#L5633-L5636)
on `diagnostic_endpoints` being `Some`, so it’s a no-op when diagnostics
are off). This keeps diagnostic state fresh across seeks triggered by
`BlockChunks::advance` past code-lens blocks, so short `Unnecessary`
regions wholly inside the post-block range now dim correctly.
Self-Review Checklist:
- [x] 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
- [x] Performance impact has been considered and is acceptable
Closes#55975.
Release Notes:
- Fixed unnecessary-code dim sometimes disappearing when `code_lens` and
`semantic_tokens: "full"` are both enabled
## Summary
DirectWrite treats U+2028 (line separator) and U+2029 (paragraph
separator) as mandatory line breaks even with word wrapping disabled.
GPUI expects no line breaks in its shaping, and our windows
implementation actually errors due to this, which causes a follow up
assertion to fail.
Adapt the segment-and-join approach already used by the Cosmic Text
backend for Windows: shape segments ending in these separators, then
concatenate their glyphs horizontally.
Closes DELTA-1WR
Closes DELTA-1WS
Release Notes:
- [GPUI] Fixed a Windows text-shaping crash caused by Unicode line and
paragraph separators.
ACP numbers lines from 1, and agents send tool call locations that way.
For example, Claude's adapter sends a Read's `offset ?? 1` and an Edit
hunk's `newStart`. Zed read a location's `line` as a 0-based row, so
following an external agent, or opening a location from a tool call,
landed one line below the reported line.
Zed's own Edit, Grep, and Read tools sent 0-based location lines to
match, which was off by one for every other location.
This PR:
- Reads a location's line as 1-based when resolving it (`acp_thread`)
and when opening it from the thread view (`agent_ui`).
- Sends 1-based location lines from the native Edit, Grep, and Read
tools.
Only the ACP `ToolCallLocation` changes. What the model sees and sends
was already 1-based: Read's `start_line`/`end_line` inputs, its numbered
output, and Grep's `#L` links. Locations aren't persisted for native
threads, so there is no stored data to migrate.
Release Notes:
- Fixed external agents' tool call locations opening one line below the
line the agent reported.
Found while investigating
[#62822](https://github.com/zed-industries/zed/issues/62822).
If you turned on `focus_follows_mouse` while Zed was already running,
docks wouldn't pick it up until you restarted. Panes worked fine right
away, but hovering a dock (like the project panel) did nothing.
The dock read the setting once when it was created and never updated it
after that. Now it just reads the setting when it renders, which is what
the project panel already does for its blank area.
Release Notes:
- Fixed changes to `focus_follows_mouse` not applying to docks until Zed
was restarted.
This PR adds some refactoring to the submenu implementation mainly to
make it feel more reliable and steady. We were previously doing a few
unnecessary calculations that'd make the submenu feel finicky
particularly when it opened on the right. Now, we're essentially better
calculating the trigger's bounds and using that as the main point of
reference, without having to calculate the entire parent menu to find
the trigger.
Release Notes:
- N/A
## Summary
I use Claude Code in a terminal thread with the agent panel zoomed, and
I couldn't get back to the project panel by clicking its button in the
status bar: the button flickers and I stay in the agent panel. The
keybinding for the same action (`cmd-1` in the JetBrains keymap) works
fine. It happens with any two panels in the same dock, not only the
agent panel.
The cause: before dispatching its action, a panel button focuses the
dock's focus handle (added in #34590 so the action works when nothing is
focused yet). But when a panel is zoomed, the dock isn't rendered,
because the panel is drawn in the zoom layer instead. So the dock's
focus handle isn't in the rendered frame, the action is dispatched from
the window root, and it never reaches the workspace's handlers.
The fix: when the dock has a zoomed panel, the button focuses that panel
instead, since it's on screen. Otherwise nothing changes.
AI helped me find the cause and write the tests; I've reviewed and
tested the change myself.
## Testing
Tested manually on macOS:
1. Open the agent panel in the left dock (the project panel is in the
same dock).
2. Zoom the agent panel.
3. Click the Project Panel button in the status bar.
Before: nothing happens. After: the project panel opens and gets focus.
I also added two tests that switch from a zoomed panel to another panel
in the same dock: one through the panel button path and one through the
action. The button test fails without the fix.
## Self-review
- [x] I've reviewed my diff for quality, security, reliability, and
performance.
- [ ] UI changes follow the
[checklist](https://zed.dev/docs/development/ui-checklist). (no visual
changes)
- [x] Tests cover the new or changed behavior.
Release Notes:
- Fixed status bar panel buttons doing nothing when another panel in the
same dock is zoomed
---------
Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com>
Closes https://github.com/zed-industries/zed/issues/9307
Use SDK 26 and require newer macOS.
The latter allows to remove a few deprecated API usages.
Release Notes:
- [GPUI] BREAKING: bumped minimum macOS version to 12 (Monterey)
The hash-based text layout interface was introduced for an earlier Delta
editor prototype, but neither Zed nor Delta has any remaining callers.
Let's remove it and re-introduce it proper when needed.
Release Notes:
- [GPUI] Removed an unused hash-based text layout cache interface.
## Summary
There isn't really any reason for us to use synchronization here at this
layer. `WindowTextSystem` gains little from being `Send`, allowing us to
simplify this a bit.
Release Notes:
- [GPUI] Improved per-window text layout performance by removing
unnecessary synchronization.
Closes#62283Closes#58444
Follow-up #65304
Supersede #64000, #62301
Before every message, the agent snapshotted every Git repo in the
project and waited for it before sending the prompt, and every Git
status change during a turn took another one. In large workspaces this
took tens of seconds, and on Windows it could hang forever. #65304
already skipped it for external agents and subagents.
The snapshot only exists for "Restore Checkpoint", which very few people
use, so this removes checkpoints entirely. Putting them behind a setting
would keep the snapshot code and its maintenance around for a feature
few people use.
- Removed:
- "Restore Checkpoint" button
- Snapshots before, during and after each turn
- Git, remote and proto code behind them (proto ids reserved)
- Checkpoints docs section
- Stays:
- Editing an earlier message
- Rejecting the agent's edits
- Worktree archive snapshots
Release Notes:
- Removed agent checkpoints and the "Restore Checkpoint" button. Taking
a checkpoint before every message made the agent slow to respond, or
hang, in large Git repositories. To undo the agent's changes, reject its
edits or use Git.
## Summary
- **Close button**: "Close Details Panel" with its keybinding
(`menu::Cancel`). It uses
`Tooltip::for_action_in` with the Git Graph's focus handle, so the
keybinding shown doesn't
change depending on what else is focused (e.g. with the terminal
focused, `Tooltip::for_action`
showed a different binding than the one that works in the Git Graph).
- **Commit message disclosure**: "Show Commit Message" / "Hide Commit
Message", matching the
existing "Show/Hide Commit Details" disclosure in the same panel.
- **"View on <provider>" button**: "Open in Browser". The label is
truncated when the panel is
narrow, so the tooltip also makes the action clear in that case.
**Close button**
<img width="538" height="236" alt="image"
src="https://github.com/user-attachments/assets/524103cc-91ba-4357-974e-23c47d681b74"
/>
**Commit message disclosure**
<img width="316" height="249" alt="image"
src="https://github.com/user-attachments/assets/b9ab5379-29f2-4010-9d7f-7610966d50dc"
/>
**View on GitHub**
<img width="349" height="114" alt="image"
src="https://github.com/user-attachments/assets/84aabae0-8f84-43d8-9c2a-b4b123ea52f7"
/>
Release Notes:
- Improved Git Graph commit details panel by adding missing tooltips to
the close, commit message, and "View on" buttons.
---------
Co-authored-by: Remco Smits <djsmits12@gmail.com>
## Summary
Currently the git graph canvas and ref-label gutter widths were computed
in `render` from `RedistributableColumnsState::cached_container_width`,
which is only updated during prepaint and doesn't notify. When the
commit details panel opened or closed, the graph column was rendered
with the previous frame's container width and stayed stale until
something else triggered a re-render, such as the commit diff finishing
loading or hovering a row.
We now size the canvas and gutter through layout instead, the canvas
fills the graph column with a minimum of its content width, and the
gutter is capped at half the graph column via `max_w(relative(0.5))`.
**Before**:
https://github.com/user-attachments/assets/ee3fcfc6-e392-491c-bd3c-827eb64ecb37
**After**:
https://github.com/user-attachments/assets/518f0c3f-603d-4f99-a391-1ff546ccaf7e
## Testing
You can test this by opening the Git graph for the Zed repository and
scrolling down to a section with a lot of graph lines.
Click a commit to open the commit details panel. You may already notice
some lag, but it's less visible because loading the commit details
triggers several re-renders.
Then close the commit details panel. This is where the lag is most
noticeable. Closing the panel triggers only a single re-render, and that
render still uses the previous frame's cached container width. Updating
the cached width doesn't trigger another re-render, so the graph stays
at its old size until something else does, such as hovering a row.
I also tested that adding/removing columns still works the same, and
shrinking/growing the graph will works.
## Self-review
- [x] I've reviewed my diff for quality, security, reliability, and
performance.
- [x] UI changes follow the
[checklist](https://zed.dev/docs/development/ui-checklist).
- [x] Tests cover the new or changed behavior.
Release Notes:
- Fixed git graph draw lagging behind when opening/closing the commit
view
## Summary
- Remove project group rows even when no retained workspace backs them.
- Add a regression test for removing an unloaded project group.
## Testing
- `cargo test -p workspace
test_remove_unloaded_project_group_removes_its_row --lib`
- `cargo fmt --check`
## Self-review
- [x] I've reviewed my diff for quality, security, reliability, and
performance.
- [x] UI changes follow the
[checklist](https://zed.dev/docs/development/ui-checklist).
- [x] Tests cover the new or changed behavior.
Release Notes:
- Fixed project entries reappearing in Recent Projects after removal.
With the `acp-beta` flag on, Zed's ACP v1 `initialize` request
advertises the unstable
[subagents](https://agentclientprotocol.com/rfds/subagents) capability
(`clientCapabilities.subagents: {}`). v1 agents that support it, such as
claude-agent-acp, then report their subagents as child sessions, which
Zed shows as inline cards. Without the flag nothing changes. v2 is
already behind the same flag and has subagents in its baseline.
Release Notes:
- N/A
A native subagent that's resumed gets one `spawn_agent` tool call per
run. `AcpThread::tool_call_for_subagent` returned the first, so the
subagent's titlebar showed the first run's failed or canceled marker
instead of the current run's. It now returns the latest. The titlebar is
its only caller.
`test_tool_call_for_subagent_is_its_latest_run` covers a failed first
run followed by a running one, and fails without the change. `cargo
nextest run -p acp_thread -p agent_ui -p agent` (1668 tests),
`./script/clippy` and `cargo fmt` pass locally.
Release Notes:
- N/A
Every thread view made its thread the inline review target when it was
built (`AgentDiff::set_active_thread` in
`ConversationView::new_thread_view`). A subagent's view is built when
the subagent is spawned or announced, not when it's opened. So as soon
as a native or ACP subagent started, inline review in the editor
switched to that subagent's action log and showed only its edits. The
parent's earlier edits disappeared from review.
A subagent's action log is linked to its parent's, and every edit it
records is also recorded there. So only root thread views set the review
target now, and the root's log covers the whole conversation.
`test_subagent_views_keep_the_root_thread_under_review` registers a
subagent and then navigates to its view. Review stays on the root thread
both times. The test fails without the change, and uses a new test-only
`AgentDiff::reviewed_thread`. `cargo nextest run -p agent_ui -p agent -p
sidebar` (1526 tests), `./script/clippy` and `cargo fmt` pass locally.
Release Notes:
- Fixed inline review switching to a subagent's edits when the subagent
started.
A tool call carrying Zed's private `_meta.subagent_session_info` makes
the conversation `load_session` the referenced session. That's how Zed
restores native subagents. Some external agents send the same key,
according to #65120, so that path stays for them.
Where the ACP subagents RFD applies, though, subagents are discovered
only through their parent's announcements, and loading one is forbidden.
Loading a referenced child before its announcement would also make the
connection reject the announcement, because the connection already
routes that session.
- `AgentConnection::announces_subagents` says whether the RFD applies:
always on v2, on v1 when Zed advertised `subagents` (behind `acp-beta`),
and never for the native agent.
- `ConversationView::load_subagent_session` does nothing where it
applies.
Without `acp-beta` nothing changes, because no connection announces
subagents.
`test_referenced_subagents_load_only_without_the_subagents_rfd` checks
both cases with a stub connection that supports loading, and fails
without the guard. Existing v1 and v2 tests now assert each connection's
answer. `cargo nextest run -p acp_thread -p agent_servers -p agent_ui -p
agent -p sidebar` (2010 tests), `./script/clippy` and `cargo fmt` pass
locally.
Release Notes:
- N/A
After a load or resume with replay, #66061 cleared each subagent's
replayed `cancel` grant and running state but kept a replayed idle
outcome (completed, canceled, failed). That exception was there because
claude-agent-acp sent no current state after the response.
claude-agent-acp now sends each replayed subagent's current state after
the response (agentclientprotocol/claude-agent-acp#1423, merged), as the
subagents RFD requires. So Zed now follows the RFD as written: every
replayed work state, outcomes included, is history. Each subagent's
state is unconfirmed until the agent reports a current one. Titles and
transcripts stay.
Release Notes:
- N/A
An ACP v2 agent can send updates before its `session/new` response; Zed
holds them until the response names the session
(`PendingSessionUpdates`). Only the new session's own updates were
handed over. A subagent it announced in that window was created, but the
subagent's own traffic was discarded when the creation ended.
- `PendingSessionUpdates::take` now also hands over traffic for sessions
the new session announced, and for the sessions those announced, in
arrival order. The subagents RFD requires a child's announcement to come
before its traffic.
- The `new_session` apply loop delivers each held update to its own
session's thread. It used to apply all of them to the new session.
Traffic for a session nobody announced is still dropped. v1 has no
pre-response staging and is unchanged.
`v2_new_session_keeps_subagent_traffic_sent_before_its_response` sends a
child, a nested grandchild announced on the child's stream, traffic for
both, and traffic for an unannounced session, all before the response.
It fails without the change. `cargo nextest run -p acp_thread -p
agent_servers -p agent_ui -p agent -p sidebar` (2010 tests),
`./script/clippy` and `cargo fmt` pass locally.
Release Notes:
- N/A
## Summary
Fix Windows file links into WSL projects, including Agent links and `zed
path:line`. Preserve the original path prefix in
`PathWithPosition::parse_str` instead of rebuilding it with the host
platform's separator.
Closes#65323. Fixes a regression introduced in #64748.
Windows regression test output before the fix:
```text
left: "/home/user/project/src\\main.rs"
right: "/home/user/project/src/main.rs"
```
The test passes after the fix. It compares raw `OsStr` values because
Windows `Path` equality hides separator differences.
## Testing
- Manually tested the patched Windows client connected to WSL: clicking
the previously failing Agent link opens the correct file as expected.
- Verified that the development CLI opens `llm_engine.py:49:7` at line
49, column 7 in the Windows GUI.
- Utility tests: **122 passed** on Linux; path-position tests: **7
passed** with each Windows GNU/MSVC target.
- Windows client, CLI, and matching WSL server builds passed, along with
Clippy, formatting, and `git diff --check`.
To verify, connect a patched Windows client to a WSL project. Have the
Agent produce a Markdown link to an existing file using its absolute WSL
path with `:line` or `:line:column`. Click it and verify the file and
cursor position. Also check the same path through the matching
development CLI.
## Self-review
- [ ] I've reviewed my diff for quality, security, reliability, and
performance.
- [ ] UI changes follow the
[checklist](https://zed.dev/docs/development/ui-checklist). (N/A: no
visual changes.)
- [x] Tests cover the new or changed behavior.
Release Notes:
- Fixed file links with line numbers failing to open WSL files when
using Zed on Windows.
---------
Co-authored-by: Kirill Bulatov <kirill@zed.dev>
Co-authored-by: Kirill Bulatov <mail4score@gmail.com>
Fixes the `main` failure in `v2_subagent_config_options_are_read_only`
(Linux, macOS and Windows `run_tests` since #66058).
#66059 and #66058 passed CI separately, but together they disagree.
`AcpV2Connection::session_config_options` returned `None` for a subagent
before reaching #66058's read-only provider. So that provider was never
used: subagents showed no configuration, and the #66058 test failed.
- Subagents now get `ReadOnlyConfigOptions`, which refuses
`set_config_option`. That's what #66059's early return was there to
guarantee.
- The provider is chosen with the same `is_subagent` check that close
and reopen use, instead of a second rule reading the thread's
`parent_session_id`.
- #66059's test now expects a read-only provider instead of none.
`cargo nextest run -p acp_thread -p agent_servers -p agent_ui -p agent
-p sidebar` (2009 tests, including both subagent config tests),
`./script/clippy` and `cargo fmt` pass locally.
Release Notes:
- N/A
ACP subagents now get the same inline card as native subagents. The
anchor is the parent's outgoing session message to the subagent, which
claude-agent-acp now reports when it launches one
(agentclientprotocol/claude-agent-acp#1405). The card replaces that
message's "To …" row.
- **One card per subagent for now.** The first message the parent sends
to one of its own subagents becomes the card; later messages to the same
subagent stay rows. Until session messages can name each other
(agentclientprotocol/agent-client-protocol#2465), nothing links a
message to its part of the subagent's transcript or to its outcome, so
the card covers the whole subagent. claude-agent-acp sends one such
message per subagent, at the launch.
- **Status** comes from the subagent's reported state:
| Reported state | Card |
|---|---|
| running, requires action | Running |
| idle, with no stop reason, `end_turn`, or one this version doesn't
know | Completed |
| idle, `cancelled` | Canceled |
| idle, `error`, `refusal`, `max_tokens`, `max_turn_requests` | Failed,
with the error text |
| no state yet, `unknown` | Unknown (new status) |
- **Title:** the parent's label for the subagent wins over the
subagent's own title, as on the permission row.
- **Stop** is offered only while the subagent runs and only when its
parent advertises `cancel` for it. The subagent's own titlebar now
follows the same rule. It also showed a failed or canceled ACP subagent
with a green check, because it read the outcome from a native tool call
that ACP subagents don't have.
- **Expansion** is keyed by a new `SubagentCardId` (a tool call or a
session message), so cards no longer need a tool-call ID.
- **Thread search** skips a message drawn as a card, since the card
doesn't show its text.
- **Redraw fix:** `update_subagent_association` only notified the
subagent's thread, so views that read the association from the parent's
side (the card, the permission row's label) didn't redraw when it
changed. It now emits `AcpThreadEvent::SubagentAssociationUpdated`.
Release Notes:
- N/A
Show the actual configuration reported by exposed ACP subagents without
offering controls their sessions do not support.
- Register an empty config provider when a child is announced, so the
first asynchronous snapshot reaches the UI in both ACP versions.
- Expose a read-only provider that rejects configuration mutations
before sending a wire request.
- Render child settings as labels below the transcript, including
boolean values, while leaving the message composer unavailable.
- Block picker/cycling actions and stale controls from changing child
settings or saving defaults.
- Test snapshot replacement, watcher updates, parent isolation, and
read-only behavior.
Protocol clarification:
https://github.com/agentclientprotocol/agent-client-protocol/pull/2468
Claude adapter implementation:
https://github.com/agentclientprotocol/claude-agent-acp/pull/1417
Release Notes:
- N/A
The RFD distinguishes two cases:
1. **Zed cancels a session's work.** Zed must answer that session's
pending permission requests with `cancelled`.
2. **A descendant's work stops because an ancestor was cancelled.** Its
requests stay answerable until it reports idle with `cancelled`; then
Zed cleans them up as if it had cancelled the descendant directly. Idle
with another stop reason does not withdraw requests, which may belong to
background work that continues.
Changes, all limited to ACP subagents (threads with a subagent
association):
- **Cancel needs permission.** `AcpThread::cancel` refuses an ACP
subagent unless its parent advertises `cancel` for it. The UI already
hides Stop without it (#66040); this makes the rule hold for any caller.
- **Direct cancel answers every request.** Cancelling an ACP subagent
now also answers its tool-call permission requests, which only a v1
subagent makes; before, only generic requests were answered. Other
sessions with reported activity keep their current behavior:
`test_reported_activity_survives_rejection_and_idle_keeps_unrelated_actions`
relies on a receipt session keeping tool-call requests.
- **Cleanup on a reported cancellation.** When an ACP subagent reports
idle with `cancelled`, Zed answers its pending permission requests,
dismisses its elicitations, and marks its unfinished tool calls
cancelled (`cancel_local_actions`). Zed never cascades a cancel to
subagents itself; it learns which ones stopped from their reported
state.
Release Notes:
- N/A
The v2 connection already refused to close a subagent. It now also:
- **Offers no config options for a subagent.** A `config_option_update`
for a subagent session used to create config options on its
`AcpSession`, and `session_config_options` then handed them out. Nothing
reached the wire: subagent views have no message editor, where the
selectors are drawn, and setting an option through the config keyboard
actions failed validation because subagents have no `session_owners`
entry. This makes the refusal explicit instead of relying on that.
- **Refuses load and resume for a subagent it routes.** `open_session`
only checked root sessions, so it would have sent `session/resume` for a
known subagent.
`AcpSession` gains `is_subagent`, set only when a parent announces the
session. All three checks (close, config, open) read it through one
helper. The previous close check read the thread's association instead,
but `open_session` can run while the session's thread is being updated
(`v2_resume_sdk_shares_compatible_opens_and_rejects_context_or_history_changes`
reopens from inside the thread's update), and reading the thread there
panics.
Release Notes:
- N/A
ACP v1 awaited `session/load` and `session/resume` responses with
`block_task`, so the SDK kept delivering the agent's later messages
before Zed had applied the response. A subagent's current state sent
right after a load response could be applied first and then overwritten
by the response.
- **Ordered responses:** load and resume now use `ordered_response`.
Once the response arrives, the agent's later messages wait until
`open_or_create_session` has applied it, as v1 `new_session` and v2
already do. An abandoned load releases them before closing its session,
which needs the agent's reply.
- **Replay boundary:** a successful v1 load, which replays history, ends
with `invalidate_replayed_subagent_state`, as a v2 resume with replay
does. v1 resume doesn't replay, so it's unchanged.
Release Notes:
- N/A