This fixes a race condition that could occur when using the sidebar:
`Failed to launch: project state not found`
We were accessing/creating the project state before an await point,
meaning that we could remove the state if session/close was called in
the meantime.
- [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:
- N/A
Closes#51309
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:
- Improved `editor::CopyFileLocation` command to include the full
selected line range (e.g. 'src/main.rs:12-18') when multiple lines are
selected, rather than only the first line number.
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:
- N/A
https://github.com/zed-industries/zed/pull/42837 added the
`cursor_offset_on_selection` field, which displays the cursor *after*
the end of the selection unless a vim visual mode is enabled, in which
case it gets displayed *at* the end of the selection.
However, the real helix is effectively *always* in select mode, and will
always display the cursor at the end of the selection, whether that
selection is made via its visual mode, a movement key, or with the
mouse.
This makes it so that the helix mode setting is taken into account
regardless of the visual-ness of the vim mode in the `sync_vim_settings`
method.
I also considered simply moving `Mode::HelixNormal` up to the `true` arm
of the match in the `is_visual` method since helix is kinda *always* in
visual mode, but I figured that could have some unintended consequences
and chose to err on the side of caution.
Possibly related to #20121Closes#46998
Release Notes:
- Fixed the cursor offset in non-visual helix selections
Co-authored-by: Nils Koch <mail@nilskch.dev>
The edit prediction, web search and completions endpoints in Cloud all
use tokens called LlmApiToken. These were independently created, cached,
and refreshed in three places: the cloud language model provider, the
edit prediction store, and the cloud web search provider. Each held its
own LlmApiToken instance, meaning three separate requests to get these
tokens at startup / login and three redundant refreshes whenever the
server signaled a token update was needed.
We already had a global singleton reacting to the refresh signals:
RefreshLlmTokenListener. It now holds a single LlmApiToken that all
three services use, performs the refresh itself, and emits
RefreshLlmTokenEvent only after the token is fresh. That event is used
by the language model provider to re-fetch models after a refresh. The
singleton is accessed only through `LlmApiToken::global()`.
I have tested this manually, and it token acquisition and usage appear
to be working fine.
Edit: I've tested it with a long running session, and refresh seems to
be working fine too.
Release Notes:
- N/A
---------
Co-authored-by: Marshall Bowers <git@maxdeviant.com>
Co-authored-by: Jakub Konka <jakub@zed.dev>
Closes #ISSUE
Before you mark this PR as ready for review, make sure that you have:
- [ ] Added a solid test coverage and/or screenshots from doing manual
testing
- [ ] Done a self-review taking into account security and performance
aspects
- [ ] Aligned any UI changes with the [UI
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
Release Notes:
- Fixed issues with tremendous audio latency in long-running collab
calls.
Co-authored-by: Jakub Konka <jakub@zed.dev>
## Summary
Angle brackets in TSX (`<`, `>`, `/>`, `</`) are always paired with JSX
tag syntax — they don't indicate bracket nesting depth — so rainbow
colorization adds noise without useful information.
This mirrors #46808, which applied the same fix to the HTML extension.
## Changes
- Added `(#set! rainbow.exclude)` to all three angle bracket patterns in
`crates/languages/src/tsx/brackets.scm`
## Before / After
Before: angle brackets in JSX tags receive rainbow colors alongside
`{}`, `()`, `[]`, making every tag visually noisy.
After: only `{}`, `()`, and `[]` receive rainbow colors — angle brackets
are excluded, matching the HTML extension behavior.
> Screenshots: I don't have a built copy of Zed handy to attach — happy
to add one if a maintainer needs it before merging.
Release Notes:
- Removed rainbow bracket colorization for angled brackets within TSX.
When the mouse cursor moves into the whitespace of a line within a
multi-line diagnostic range, the hover popover would previously
disappear. This change adds a check to keep the diagnostic hover visible
if the mouse row intersects with the active diagnostic's range.
Fixes#46841
Release Notes:
- Improved hover behavior for multi-line diagnostics to persist when
hovering over whitespace.
https://github.com/user-attachments/assets/0965cb25-6207-4d4a-9165-0d51157fc6e4
Before, both rust-analyzer's LSPext tasks and tree-sitter tasks were
queried on the entire multi buffer range.
The PR moves all runnable-related logic into a submodule, and reworks
the logic to consider only the visible buffers.
Singleton buffers have their tasks resolved for the entire range still
(same as LSPext tasks work), multi buffers have their buffers' data
cached and reused.
Release Notes:
- Improved multi buffer's runnables resolution performance
Follow up to https://github.com/zed-industries/zed/pull/49807
This PR fixes the merge conflict notification by making it appear only
once per a given set of conflicted paths, as opposed to showing every
time the `ConflictsUpdated` or `StatusesChanged` even would fire.
Release Notes:
- N/A
Fixes a panic in livekit's process_reverse_stream for non-matching
channel counts, e.g., upmixing 2->4, or downmixing 2->1.
Release Notes:
- Fixed a panic in livekit when joining a channel using legacy audio
using a device with less or more than 2 channels.
This will allow us to test changes against just a subset of extensions.
Another advantage is that extension workflows will be pinned, which
allows for easier debugging and better predictability.
Release Notes:
- N/A
Run `pylsp --version` via `delegate.try_exec()` in both branches of
`PyLspAdapter::check_if_user_installed` before returning the binary. If
execution fails (broken shebang, missing interpreter, etc.), log a
warning and return None so the system falls through gracefully instead
of surfacing an error dialog.
This matches the existing validation pattern used by TyLspAdapter and
RuffLspAdapter in their `fetch_server_binary` implementations.
No idea if this closes an issue but it sure was annoying on a system
where I deleted the pylsp environment I had. It surprised me too since I
had pylsp disabled in settings.
Release Notes:
- Fixed detection of when `pylsp` is not installed properly on a user's
system so that it doesn't get launched as an LSP when it doesn't exist.
* [x] Put back persistence of sidebar open state
* [x] when agent panel is docked right, put sidebar on the right side
* [x] remove stale entries from `SidebarsByWindow`
Release Notes:
- N/A
---------
Co-authored-by: Eric Holk <eric@zed.dev>
Co-authored-by: Mikayla Maki <mikayla.c.maki@gmail.com>
Co-authored-by: Anthony Eid <hello@anthonyeid.me>
String panics are a non-trivial percentage of the crashes we see at Zed,
and
doubly unfortunately they may incidentally include the contents of a
user's
buffer.
Although this hasn't happened yet (to my knowledge), I don't want to be
in the position of having received sensitive information this way.
See also https://github.com/rust-lang/rust/pull/153677
Release Notes:
- N/A
This PR adds a bool method to the `ListItem` that allows to turn on the
gradient overlay in the `end_hover_slot`. Places that are not the
sidebar, at least at the moment, don't need it. And with the previous
code, they were getting it, which felt wrong.
Release Notes:
- N/A
As a follow up to the possibility of sending the branch diff to an agent
review, this PR enables directly @-mentioning the content of your diff
with main to the agent. Here's a quick video of it:
https://github.com/user-attachments/assets/f27b7287-c9b9-4ccf-875e-4ac6ce4cd8ad
Release Notes:
- Agent: Enabled mentioning the branch diff with main.
This PR adds a Danger check to remind contributors that any database
changes for Collab need to be done via a migration in the Cloud repo:
<img width="888" height="323" alt="Screenshot 2026-03-10 at 6 39 21 PM"
src="https://github.com/user-attachments/assets/5b3bbc3d-1e9d-409a-837b-565e1ca36935"
/>
Release Notes:
- N/A
Closes#51011
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:
- N/A *or* Added/Fixed/Improved ...
I did a search for `/^line_comments = .*[^\s\[]"/` to identify these 3
languages:
- Git Commit
- Go Mod
- Go Work
that don't add/remove a trailing space for inline comments. I couldn't
find any indication that the absence of the trailing space is due to any
peculiarity of these languages.
---
For Git Commit, I should note that (strictly speaking) the comment
character is a single `#` without a trailing space, as Git removes any
line starting with the default comment character (`#`) (see
https://git-scm.com/docs/git-config#Documentation/git-config.txt-corecommentChar).
But I believe this change only affects whether `editor::ToggleComments`
adds/removes the space, and not how the file is syntax highlighted. So
for aesthetics and consistency, it should be better to add/remove the
trailing space.
---
Before you mark this PR as ready for review, make sure that you have:
- [ ] Added a solid test coverage and/or screenshots from doing manual
testing
- [ ] Done a self-review taking into account security and performance
aspects
- [ ] Aligned any UI changes with the [UI
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
Release Notes:
- Add/remove a space when toggling inline comments in Git Commit and Go
Mod/Work languages
## Summary
This fix addresses the cross-platform root cause identified in issue
#38109 where open buffers go stale or empty when external tools write
files.
## The Problem
The buffer's `file_updated()` method was only comparing `mtime` to
determine if a buffer needed to be reloaded. This caused a race
condition when external tools write files using `std::fs::write()`,
which uses `O_TRUNC` and creates a brief window where the file is 0
bytes:
1. Scanner re-stats → sees 0 bytes, mtime T
2. `file_updated()` sees mtime changed → emits `ReloadNeeded`
3. Buffer reloads to empty, stamps `saved_mtime = T`
4. Tool finishes writing → file has content, but mtime is still T (or
same-second granularity)
5. Scanner re-stats → mtime T matches `saved_mtime` → **no reload
triggered**
6. Buffer permanently stuck empty
## The Fix
Release Notes:
- Add the file `size` to `DiskState::Present`, so that even when mtime
stays the same, size changes (0 → N bytes) will trigger a reload. This
is the same fix that was identified in the issue by @lex00.
## Changes
- `crates/language/src/buffer.rs`: Add `size: u64` to
`DiskState::Present`, add `size()` method
- `crates/worktree/src/worktree.rs`: Pass size when constructing File
and DiskState::Present
- `crates/project/src/buffer_store.rs`: Pass size when constructing File
- `crates/project/src/image_store.rs`: Pass size when constructing File
- `crates/copilot/src/copilot.rs`: Update test mock
## Test plan
- [ ] Open a file in Zed
- [ ] Write to that file from an external tool (e.g., `echo "content" >
file`)
- [ ] Verify the buffer updates correctly without needing to reload
Fixes#38109
---------
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-authored-by: Ben Kunkle <ben.kunkle@gmail.com>
Co-authored-by: Jakub Konka <kubkon@jakubkonka.com>
Closes #ISSUE
Before you mark this PR as ready for review, make sure that you have:
- [ ] Added a solid test coverage and/or screenshots from doing manual
testing
- [X] Done a self-review taking into account security and performance
aspects
- [ ] Aligned any UI changes with the [UI
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
Release Notes:
- Enabled `diff_stats` in the git panel by default.
Closes#48697
Supersedes #48698
Related to #38109
## Problem
If you edit a file and an external tool writes to it while you have
unsaved changes, Zed tracks the new file but skips the reload to
preserve your edits. If you then undo everything, the buffer goes back
to clean but still shows the old content. The disk has moved on, but
nothing triggers a reload.
## Fix
In `did_edit()`, when the buffer transitions from dirty to clean, check
if the file's mtime changed while it was dirty. If so, emit
`ReloadNeeded`. Only fires for files that still exist on disk
(`DiskState::Present`).
7 lines in `crates/language/src/buffer.rs`.
### No double reload
`file_updated()` suppresses `ReloadNeeded` when the buffer is dirty
(that's the whole bug). So by the time `did_edit()` fires on
dirty-to-clean, no prior reload was emitted for this file change. The
two paths are mutually exclusive.
## Test plan
- New: `test_dirty_buffer_reloads_after_undo`
- No regression in `test_buffer_is_dirty` or other buffer tests
- All project integration tests pass
- clippy clean
Release Notes:
- Fixed an issue where buffer content could become stale after undoing
edits when an external tool wrote to the file while the buffer was
dirty.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Ben Kunkle <ben@zed.dev>
This removes the assumption that one project <-> one native agent. The
native agent now maintains a project per session. We don't make use of
this right now, but it will come in handy once we start sharing ACP
connections globally.
Release Notes:
- N/A