Commit Graph
39560 Commits
Author SHA1 Message Date
PriyadharshanandChristopher Biscardi f652da59e8 Added Tracked , Staged options to stash (#62254)
# Objective

Closes #62252 

The Git Panel could only stash *everything* — `Stash All` runs
`git stash push --include-untracked`, sweeping tracked edits and
untracked files
into a single entry. There was no way to stash a subset, so the common
workflows
of "park my tracked edits but keep my new scratch files" and "park what
I've
staged and keep working on the rest" required dropping to the terminal.

## Images

<img width="389" height="358" alt="Screenshot 2026-08-10 at 3 10 50 PM"
src="https://github.com/user-attachments/assets/18e4c943-e320-4802-ada8-59e54bf4cefd"
/>

<img width="504" height="462" alt="Screenshot 2026-08-10 at 3 10 37 PM"
src="https://github.com/user-attachments/assets/783237eb-980d-47bc-a0f5-17b03a23a60c"
/>






## Solution

Add two stash variants alongside `Stash All`, surfaced in the Git
Panel's
overflow menu based on how the list is currently grouped, so the menu
mirrors the
sections the user can actually see:

| Group By | Stash entries offered |
| --- | --- |
| None | Stash All |
| Tracked & Untracked | Stash All, **Stash Tracked** |
| Staged & Unstaged | Stash All, **Stash Staged** |

- **`git::StashTracked`** stashes tracked changes and leaves untracked
files in
place. It reuses the existing pathspec plumbing
(`Repository::stash_entries`),
  filtering the status list down to the paths to stash.
- **`git::StashStaged`** stashes the index only, leaving unstaged
changes in
place. This *cannot* be expressed as a pathspec — a partially staged
file would
have its unstaged hunks stashed too — so it needs git's own `--staged`
flag.
  That meant a new `GitRepository::stash_staged` backend method and an
`optional bool staged` field on `proto::Stash` so remote projects work
too.

Both actions are unbound by default and are dispatchable from the
command palette
when the panel is focused.

One subtlety worth calling out for review: `Stash Tracked` filters on
`FileStatus::is_created()`, not `is_untracked()`. Staging a new file
flips it from
`Untracked` to `Tracked { Added }`, but the panel still lists it under
**Untracked** — using `is_untracked()` meant staged-new files were
silently
stashed. `is_created()` is the same predicate the panel uses to build
that section
(`git_panel.rs`), so the menu item and the list can no longer disagree.

This branch also includes a separate commit adding **per-section
staging**
(`git::StageSection` / `git::UnstageSection`) — right-click a file to
stage or
unstage every entry in its section. Happy to split that into its own PR
if
preferred.

## Testing

Manually tested on macOS against a scratch repo with a mix of states:
modified
tracked files, untracked files, and untracked files that had been
staged.

- `Stash Tracked` with tracked edits + untracked files → only tracked
edits
  stashed; untracked files remain.
- `Stash Tracked` with untracked files **staged** → they remain, staged.
This was
  broken in an earlier revision and drove the `is_created()` fix above.
- `Stash Staged` with one file staged and another modified-but-unstaged
→ only the
  staged file is stashed; the unstaged edit and untracked files survive.
- `Stash Pop` round-trips both cases back to the original state, with no
conflicts.
- Menu contents and disabled states verified in all three Group By
modes.
- Per-section staging covered by a new unit test,
  `test_stage_section_scopes_to_selected_section`.

Not covered by automated tests: the stash actions themselves.
`FakeGitRepository`
leaves every stash method `unimplemented!()`, so stash behavior isn't
reachable
from GPUI tests today — consistent with the existing untested
`StashAll`. Adding
fake-repo stash support looks like a worthwhile follow-up but felt out
of scope here.

Reviewers on non-macOS platforms: nothing here is platform-specific.
Note that
`Stash Staged` requires **git 2.35+** (Jan 2022) for `git stash push
--staged`;
older git surfaces a clear error toast rather than failing opaquely. The
remote
path (`proto::Stash.staged`) has not been exercised against a live
collab session.

## 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)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

Release Notes:

- Added `Stash Tracked` and `Stash Staged` options to the Git Panel,
letting you stash only tracked changes or only staged changes.

---------

Co-authored-by: Christopher Biscardi <chris@christopherbiscardi.com>
2026-08-18 05:36:16 +00:00
Conrad Irwin 52f9567fb4 Preserve typed errors when listing Anthropic models (#62791)
Anthropic model-list requests currently flatten request, transport,
response, and API failures into `anyhow` strings. Callers therefore
cannot distinguish an invalid API key from connectivity or provider
failures, even though Anthropic returns a structured error payload.

This changes `list_models` to return `AnthropicError`, maps each request
stage to its existing typed variant, and routes unsuccessful responses
through the same structured response handler used by completion
requests. The language model provider converts that error at its
existing `LanguageModelCompletionError` boundary. A regression test
verifies that an authentication response retains both its error category
and Anthropic's human-readable message.

Testing performed:

- `cargo fmt --check`
- `cargo nextest run -p anthropic -p language_models`
- `./script/clippy -p anthropic -p language_models`

Release Notes:

- Fixed Anthropic API key errors being reported as generic model-list
failures.
2026-08-18 03:44:43 +00:00
Conrad Irwin 1c9e06076c open_ai: Classify Responses API send failures as transport errors (#62660)
OpenAI Responses API send failures were being converted into the
catch-all `Other` error before they reached the language model layer. A
DNS failure from the ChatGPT Subscription provider could therefore
appear as an unexpected model error instead of using the existing
transport-aware messaging and retry behavior.

The shared Chat Completions transport already preserves this
distinction. This change applies the same `RequestError::HttpSend`
classification to Responses API streaming and compaction requests,
allowing the existing conversion to produce
`LanguageModelCompletionError::HttpSend` with the provider and
underlying cause intact. Separate regression tests cover send failures
in both request paths.

Testing performed:

- `cargo test -p open_ai reports_http_send_errors -- --nocapture`
- `cargo test -p open_ai`
- `cargo check -p openai_subscribed`
- `cargo fmt --all --check`
- `git diff --check`
- `./script/clippy -p open_ai`

Release Notes:

- Fixed ChatGPT Subscription connection failures showing a generic error
instead of a network-specific message.
2026-08-18 03:20:44 +00:00
Finn Evers 477c81b92e Ensure that clippy fixes can be disabled for the autofix workflow (#62781)
Also disables them by default because it makes autofixes for the average
case very slow.

Note that this does not yet change anything for the Zippy /autofix
command here.

Release Notes:

- N/A
2026-08-17 22:50:45 +00:00
Xiaobo Liuandzed-zippy[bot] c51e4fb1b4 project: Deduplicate identical language server hover responses (#62266)
Closes https://github.com/zed-industries/zed/issues/62262

## Solution

Identical hover responses from multiple language servers should be
displayed only once.

Different hover responses should still all be preserved, since multiple
language servers may provide complementary information.


## Showcase



https://github.com/user-attachments/assets/67246d9f-ed1c-4f5a-98f5-f10548b7fc6d



---

Release Notes:

- Deduplicated identical language server hover responses

---------

Signed-off-by: Xiaobo Liu <cppcoffee@gmail.com>
Co-authored-by: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>
2026-08-17 22:47:34 +00:00
Remco SmitsandEric Holk ea68882d4b git: Allow using system pinentry in gpg wrapper script (#62357)
Closes https://github.com/zed-industries/zed/issues/61806

Follow-up to #58791 and #61265.

# Objective

Since Zed started injecting its own gpg wrapper for commit signing, the
wrapper's "silent first attempt" used `--pinentry-mode error`, which
forbids gpg-agent from launching *any* pinentry. That was meant to avoid
the `gpg: signing failed: Inappropriate ioctl for device` failure from
TTY-based pinentries, but it also blocked **GUI** pinentries like
pinentry-mac, which need no TTY and can supply the passphrase silently
from the macOS Keychain. For users with that setup (and gpg-agent's
in-memory cache disabled via `default-cache-ttl 0`), the first attempt
always failed and Zed's passphrase modal appeared on **every commit**,
even though terminal git signed silently.

This also makes the setting proposed in #61533 unnecessary: instead of
asking users to choose between Zed's prompt and the system pinentry, the
wrapper now tries the system pinentry automatically and only falls back
to Zed's askpass modal when gpg genuinely cannot obtain the passphrase
on its own.

## Solution

Restructure the wrapper script to sign in three stages, most silent
first, so every pinentry configuration self-selects the right behavior
without any detection or settings:

1. **`--pinentry-mode error`**: succeeds only via gpg-agent's passphrase
cache or an unprotected key; guaranteed to never prompt anywhere. This
keeps the #61265 behavior byte-identical.
2. **Default pinentry mode**: lets the configured pinentry run, exactly
like terminal git. GUI pinentries (e.g. pinentry-mac reading the macOS
Keychain) need no TTY and sign silently or show their native dialog; TTY
pinentries fail fast with `Inappropriate ioctl for device` because git
spawns gpg without a TTY.
3. **Loopback mode**: asks for the passphrase via Zed's askpass modal
and hands it to gpg on fd 3, for setups where gpg cannot prompt at all
(e.g. when gpg-agent's `pinentry-program` is not configured).

## Testing

Initial steps:
1. Run `security delete-generic-password -s GnuPG` to remove the GnuPG
keychain entry, forcing you to re-enter your passphrase (start from the
initial state of issue)
2. (**optional for a few test cases**) Configure your
`~/.gnupg/gpg-agent.conf` with `pinentry-program
/opt/homebrew/bin/pinentry-mac`
3. Run `gpgconf --kill gpg-agent` to force reset/kill the gpg agent
cache

Cases to test:
1. Have no existing gpg key and you can still commit without needing to
enter a passphrase
2. Have a gpg key configured in git but no `~/.gnupg/gpg-agent.conf`
config that configures the `pinentry-program`
This should still request your passphrase via Zed's askpass modal, even
though no `pinentry-program` is configured and committing via the
terminal throws an error `gpg: signing failed: Inappropriate ioctl for
device`
3. Have a gpg key configured in git and a `~/.gnupg/gpg-agent.conf`
config that configures the `pinentry-program`, and cancel the native
pinentry program → Zed should fall back to requesting your passphrase
via the askpass modal
4. Have a gpg key configured in git and a `~/.gnupg/gpg-agent.conf`
config that configures the `pinentry-program`, and fill in your
passphrase via the native pinentry program with storing your passphrase
in the keychain **disabled**
5. Have a gpg key configured in git and a `~/.gnupg/gpg-agent.conf`
config that configures the `pinentry-program`, and fill in your
passphrase via the native pinentry program with storing your passphrase
in the keychain **enabled** → subsequent commits sign silently, matching
terminal git

## 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

**After: (Testing that the system pinentry program is used and works
without needing to reenter your passphrase everytime only when you
remove it from your keychain)**


https://github.com/user-attachments/assets/0c8cdd11-957d-443a-ab10-1579bbf3b49e

---

Release Notes:

- Git: Fixed the GPG passphrase modal appearing on every commit for
users whose configured pinentry (e.g. pinentry-mac with the macOS
Keychain) can supply the passphrase without Zed's help. Zed now only
prompts when gpg cannot obtain the passphrase on its own.

---------

Co-authored-by: Eric Holk <eric@zed.dev>
2026-08-17 22:43:12 +00:00
Austin Cummingsanddino 33b0b39e40 workspace: Reset all configured dock panels (#62552)
Closes #57388.

When a dock is listed in `resize_all_panels_in_dock`, reset its
compatible panels to the active panel's default size. This applies to
the reset actions and resize-handle double-clicks. Docks not listed in
the setting continue to reset only the active panel.

Adds regression coverage for fixed panels with different defaults,
flexible panels, and active-panel-only resets.

Release Notes:

- Fixed dock size reset commands only resetting the active panel when
`resize_all_panels_in_dock` is enabled.

---------

Co-authored-by: dino <dinojoaocosta@gmail.com>
2026-08-17 22:28:04 +00:00
Cameron Mcloughlin 29202c1ab5 gpui: Frame time debug overlay (#62749)
<img width="372" height="207" alt="image"
src="https://github.com/user-attachments/assets/5e44a121-b6f3-4bb8-9f94-5bb7da1c04d2"
/>

New keybinds:
- `ctrl-alt-shift-p` - cycle debug overlay between "off", "minimal",
"full"
- `ctrl-alt-shift-o` - reset stats

---

Release Notes:

- Added: Frame time debug overlay
2026-08-17 22:17:24 +00:00
goring 484d75f0ab gpui: Fix TestWindow panicking on window_handle (#62775)
> **AI disclosure:** I used Claude (Anthropic) to diagnose this, write
the fix and its test, and draft this PR description, after every
headless test in my own app started panicking during a gpui upgrade. I
reviewed the diff and the reasoning below, ran the tests myself, and
understand and take responsibility for the change, per Zed's [AI
Policy](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#ai-policy).

# Objective

- `TestWindow` panics instead of returning an error when asked for its
raw window handle. `HasWindowHandle` and `HasDisplayHandle` both return
`Result<_, HandleError>`, so a window with no C-typed handle can report
that — but `TestWindow` calls `unimplemented!()`. Callers who correctly
write `window_handle().ok()?` still crash, and any headless test whose
window reaches code that asks for the platform handle dies on boot.
- This has two halves, and only the second made it reachable:
- `d4781bc29` ("Add raw window handle implementations to GPUI", #7101,
2024-01-30) added both impls for `TestWindow` as `unimplemented!()`
placeholders while the real platforms got real ones. `TestWindow` was
`pub(crate)` then, so nothing outside gpui could hit it.
- `386174cca` ("gpui: Implement `HasWindowHandle` on `Window`", #24327,
2025-02-06) made `Window` implement both traits by forwarding to
`platform_window`. From then on, any consumer asking a `Window` for its
raw handle reaches `TestWindow` under `TestAppContext`.
- I hit this through
[gpui-component](https://github.com/longbridge/gpui-component), whose
macOS accessibility code calls
`HasWindowHandle::window_handle(window).ok()?` on every window it roots
— correct defensive code that still panics, taking every one of my
headless `#[gpui::test]` tests down at boot.


## Solution

- `TestWindow::window_handle` and `TestWindow::display_handle` now
return `Err(HandleError::NotSupported)` instead of calling
`unimplemented!()`. That variant's documentation describes exactly this
case — "the underlying handle cannot be represented using the types in
this crate".
- Real platform windows are untouched: this only changes what the test
platform reports, so `Ok(...)` on macOS, Linux and Windows is
unaffected. Callers that already handle the error path now get the error
they were written for.

## Testing

- Added `test_window_reports_no_raw_handle_instead_of_panicking` in
`crates/gpui/src/window.rs`, asserting both calls return
`Err(HandleError::NotSupported)`.
- Reverting the fix while keeping the test reproduces the original
panic, so the test pins the behaviour rather than passing vacuously.
- `cargo test -p gpui --lib` from a clean target directory — 220 passed,
0 failed:

```
   Compiling gpui v0.2.2 (/…/zed/crates/gpui)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 5m 25s
     Running unittests src/gpui.rs (target/debug/deps/gpui-463768d254ca0c08)

running 220 tests
...
test window::tests::test_window_reports_no_raw_handle_instead_of_panicking ... ok
...
test result: ok. 220 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.49s
```
- Tested on macOS. The change is confined to
`crates/gpui/src/platform/test/`, which is platform independent, but I
have not built the Linux or Windows platform crates.

## Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [ ] Unsafe blocks (if any) have justifying comments
- [ ] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

## Showcase

Before — the new test against the current `unimplemented!()`:

```
thread 'window::tests::test_window_reports_no_raw_handle_instead_of_panicking' panicked at
crates/gpui/src/platform/test/window.rs:57:9:
not implemented: Test Windows are not backed by a real platform window

test result: FAILED. 0 passed; 1 failed
```

After — see the full run above.

Release Notes:

- N/A
2026-08-17 21:50:09 +00:00
David Barsky 611adabc57 gpui: Add spring animations; examples (#62778)
# Objective

I wanted spring animations in GPUI for an application built atop of
GPUI.

## Solution

I texted @mikayla-maki about wanting spring animations; we collaborated
in Delta; this change is the co-authored result. We built atop of GPUI's
existing APIs, but this *is* new API surface. The verbiage is borrowed
from SwiftUI's approach.

First, what _are_ spring animations? If you're unfamiliar, they're the
bouncy, physical animations that you'd often see in mobile applications.
As Claude put it to me, "keyframe animation is a recording; a spring is
a simulation". There's a few consequences:
1. The animation API needs to support interrupts/cancelation, or the
application using spring animations will feel broken. You need to cancel
the momentum in a physically realistic way!
2. The API is more complex! GPUI's existing animations are, roughly,
`Fn(progress: f32) -> eased_progress: f32`, but a spring animation is
closer to `Fn(state: SpringState, target: f32, delta_time: f32) ->
SpringState`. Concretely, GPUI landed on the following:

```
pub fn step(
    &self,
    state: SpringState,
    target: f32,
    delta_time: f32,
) -> SpringState;
```

...where `&self` is:
```
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct SpringConfig {
    /// The spring stiffness, conventionally written as $k$.
    pub stiffness: f32,
    /// The viscous damping coefficient, conventionally written as $c$.
    pub damping: f32,
    /// The moving mass, conventionally written as $m$.
    pub mass: f32,
}
```

Conceptually, at each frame, GPUI does `let state = spring.step(state,
target, delta_time);`, or as an other LLM summarized:

```
// Ordinary animation:
progress: f32 -> phase: f32

// GPUI spring:
(state: { position, velocity }, target, dt)
    -> new { position, velocity }
    -> typed presentation value
```

---

Release Notes:

- gpui: Added spring animations
2026-08-17 21:43:46 +00:00
Kirill BulatovandMrSubidubi aad8ae4b34 Fix overflowing highlights in the markdown blocks (#62714)
Before:
<img width="1728" height="1084" alt="before"
src="https://github.com/user-attachments/assets/68a33e27-7ee7-42cc-9f1b-53e541ef8d2f"
/>


After:
<img width="1728" height="1084" alt="after"
src="https://github.com/user-attachments/assets/b51df462-6457-44fd-ba83-f13c6129125d"
/>


Release Notes:

- Fixed overflowing highlights in the markdown blocks

---------

Co-authored-by: MrSubidubi <finn@zed.dev>
2026-08-17 19:07:31 +00:00
Anthony Eid 8c3e946377 Update community champions list (#62761)
# Objective

@HalavicH Has been responsible for building out our csv preview feature
and producing plenty of high qualtiy PRs to do so. I'm marking him as a
community champion to recgonize that work and give is PRs higher
priority when it comes to review

Release Notes:

- N/A
2026-08-17 19:05:13 +00:00
Ayush f3b8308c83 git_ui: Enable navigation for single-hunk diffs (#62615)
## What

Keep the hunk navigation controls available when a diff contains one
hunk, so users can return to it after scrolling away. This applies to
solo, staged, unstaged, and project diff views.

## Why

The controls were only rendered when `hunk_count > 1`, even though the
existing navigation actions already wrap and recenter a single hunk.

## How

Render the previous and next hunk controls whenever `hunk_count > 0`,
reusing the existing navigation actions.

Closes #62469

## Testing

- `cargo +stable-x86_64-pc-windows-gnu test -p git_ui --lib` — 130
passed.
- `cargo +stable-x86_64-pc-windows-gnu build -p zed -j 1` — passed.
- `rustfmt --edition 2024 --check` on the four changed files — passed.
- `git diff --check` — passed.
- Manually verified with the branch-built Zed on Windows: opened a
tracked file with exactly one diff hunk, expanded the context, scrolled
below the hunk, and used **Go to Previous Hunk**. The view returned to
the changed line.

## Showcase


https://github.com/user-attachments/assets/e7b63030-50ad-4536-8266-13987ed85f3d

## 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://zed.dev/docs/development/ux-ui) and [icon
guidelines](https://zed.dev/docs/development/ui-icons))
- [ ] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

Release Notes:

- Enable "Go to Previous Hunk" and "Go to Next Hunk" buttons even if
there's a single diff hunk.
2026-08-17 18:16:10 +00:00
Buyun Xu 3c0fad36ea project: Send diagnostic related information in code action requests (#62110)
Closes #62560.
Supersedes #62108, which was a subset of this one.
Overlaps #62400, see comments.

# Objective

Zed flattens the `relatedInformation` of a diagnostic into non-primary
entries of the same diagnostic group. Before this change it did not
retain the original related information on the primary diagnostic, so
code action requests were built from the entries intersecting the
requested range, with the primary diagnostic carrying no
`relatedInformation`.

This caused incomplete code actions from servers such as
`mlir-lsp-server`, which generates `expected-note` edits by walking the
related information of an error or warning diagnostic.

## Solution

Keep the related information the server published on the primary
diagnostic when the diagnostic comes in, next to `data`, and pass it
back when building the code action request.

Nothing is removed from `context.diagnostics`: the flattened entries are
still sent as before, so a diagnostic the server published on its own
and that Zed merged into a group as supporting information keeps being
sent with the severity the server gave it. What it does not recover is
that diagnostic's own `relatedInformation`: ingestion keeps only its
severity. Unchanged from `main`.

Reassembling it from the flattened entries instead, which is what the
first revision of this PR did, is neither faithful — ingestion trims
messages and drops entries with an empty message or pointing at another
file — nor cheap: diagnostics are not indexed by group, so every request
would scan all diagnostics of the buffer, once per server, on every
selection change.

One caveat: the stored ranges are the ones the server published rather
than anchors, so they do not follow edits made after the diagnostic
arrived, while the primary's range does. An edit in that window can put
a resolved insertion a few lines off — `mlir-lsp-server` places the
`expected-note` line at the note's own position. `data` has the same
property today. Anchoring them would mean carrying related information
through the anchor conversion, which I would rather do as a follow-up if
you consider it worth it.

The field is not carried over the proto conversion, as LSP requests are
only built by the peer that received the diagnostics from the language
server.

## Testing

New tests for:

- related information sent verbatim, including the cross-file and empty
entries that flattening drops;
- no related information;
- a flattened entry whose primary is outside the requested range;
- a server-published supporting diagnostic;
- two servers on the same buffer.

Verified on the repro from #62560 that `mlir-lsp-server` inserts both
the `expected-error` and the `expected-note` check
([screenshot](https://github.com/zed-industries/zed/issues/62560#issuecomment-5278476460)).

- `cargo test -p project`
- `cargo test -p language -p editor -p diagnostics`
- `cargo fmt --all -- --check`
- `./script/clippy -p project -p language`

## Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

---

Release Notes:

- Fixed incomplete code actions from language servers that rely on the
related information of a diagnostic.
2026-08-17 16:40:29 +00:00
vinod akshatandKirill Bulatov 97c3168848 Fix horizontal autoscroll not following cursor on long selections (#62691)
# Objective

Fixes #62524

This bug was introduced in a regression from #61487, which fixed
horizontal autoscroll for multi-row selections (word wrap off) by
computing target_left/target_right from the selection's actual start/end
instead of just head.That fix changed target_left/target_right from
always being a single point (head's column) to spanning the full
selection width. This tripped an existing guard (if target_right -
target_left > viewport_width { return None; }) whenever a selection was
wider than the viewport, previously dead code, since
target_left/target_right were never far apart before #61487. The
function now bails out before adjusting scroll at all in that case.

## Solution

In `autoscroll_horizontally`, compute the selection's span width per
row. If it exceeds the viewport width, fall back to tracking just head
(the pre-#61487 behavior) instead of the full start/end span. If it
fits, keep using the full span so the #61409 fix is unaffected.

## Testing

- Did you test these changes? If so, how?
- Tested manually in-app on macOS: selecting a long line with
cmd+shift+end now scrolls correctly.
(NOTE: I used Claude to write these unit tests for me)
- Added test_autoscroll_horizontally_long_selection_tracks_cursor:
selects a 250-character line in a narrow viewport and asserts the scroll
position moves to follow the cursor, instead of staying frozen at 0.
- Added
test_autoscroll_horizontally_fitting_selection_reveals_full_span:
selects a short span that fits within the viewport and asserts the full
span is revealed, confirming the #61409 fix still holds.
- Ran the full editor test suite locally (cargo test --package editor
--lib), all passing.

## Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [ ] Unsafe blocks (if any) have justifying comments
- [ ] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

---

Release Notes:

- Fixed horizontal scroll not following the cursor when selecting a line
longer than the viewport width

---------

Co-authored-by: Kirill Bulatov <kirill@zed.dev>
2026-08-17 16:39:45 +00:00
Marshall Bowers f5a912e5f3 docs: Fix some links (#62758)
This PR fixes some links in the docs to use relative links instead of
pointing to `docs.zed.dev` (which isn't where the docs actually live).

Release Notes:

- N/A
2026-08-17 13:30:49 +00:00
Xin Zhao 278c2751c9 language: Fix auto-indent overwriting manual indentation when replacing a line's contents (#62644)
# Objective

Closes #62617

Turns out #62617 is just a special trigger point of a more general
issue: replacing a line's contents can silently rewrite the line's
indentation with the auto-indent suggestion.

Consider the following Rust code, where the line has an extra tab,
making its indent 8 spaces instead of the default 4:
```Rust
fn main() {
        println!("hello world");
}
```
If we select and replace the line's contents (without the indentation):
```Rust
fn main() {
        «println!("hello world");»
}
```
with `let a = 8;`, the result is:
```Rust
fn main() {
    let a = 8;
}
```
The extra indent has been stripped.

Tracing this down to `Buffer::edit_internal()` in
`crates/language/src/buffer.rs`, the code decides whether the edited
line needs an indent update via the `first_line_is_new` flag, which ends
up as the `old_row` of an `AutoindentRequestEntry`. One of these checks
is:


https://github.com/zed-industries/zed/blob/f65b8464f63f0a77642e86b8e0ba0f133fef50c2/crates/language/src/buffer.rs#L2913-L2918

When replacing a line's contents, the edit range ends exactly at the end
of the line, so `old_start.column + (range_len as u32) == old_line_end`.
Because the check uses `<`, this case meets none of the these
conditions, `first_line_is_new` stays `true`, and an indent update is
triggered. If the manual indent differs from the suggested indent, it
gets overwritten — exactly as in the example above.

For IME input, composition updates replace the previously marked preedit
text, which sits at the end of the line — the same geometry as a full
line-content replacement. In some environments (observed on KDE Wayland
with fcitx), a single keystroke delivers the preedit update twice, so
the replacement happens on the very first keystroke, which is what
#62617 reports. On other platforms, the replacement may happens once the
composition changes, i.e. on the second keystroke, so it takes at least
two characters to trigger.

## Solution

Simply change the guard from `(old_start.column + (range_len as u32) <
old_line_end` to `(old_start.column + (range_len as u32) <=
old_line_end`.

## Testing

Two new tests are added: `test_ime_composition_keeps_manual_indent`
covers the IME input path, and
`test_replacing_line_content_keeps_manual_indent` covers a plain
line-content replacement.

## 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 manual indentation being lost when replacing a line's contents
or typing with an input method
2026-08-17 12:58:34 +00:00
Finn Evers 03937dfc48 ci: Restore member read permission for community workflows (#62755)
Release Notes:

- N/A
2026-08-17 12:23:47 +00:00
Kirill Bulatov 4f3ea0998f Reuse char-scan invisibles detection in highlight_invisibles (#62715)
Follow-up to
https://github.com/zed-industries/zed/pull/62478#discussion_r3769810809

New bench results:

| corpus | old | new | speedup |
|---|---|---|---|
| ascii, no invisibles | 83 MB/s | 580 MB/s | **7.0x** |
| unicode, no invisibles | 88 MB/s | 442 MB/s | **5.0x** |
| sparse invisibles | 63 MB/s | 431 MB/s | **6.9x** |
| dense invisibles | 82 MB/s | 109 MB/s | 1.3x |


Release Notes:

- N/A
2026-08-17 09:45:39 +00:00
ADITYA CHAUHAN 1a6b37d367 legal: Use absolute URLs for Terms of Service and Privacy Policy links (#62684)
Release Notes:

- Fixed broken links in the installer Terms of Service dialog (#62677).

---

### Description

Closes #62677

In `script/terms/terms.rtf` and `legal/terms.md` (as well as
`legal/privacy-policy.md` and `legal/third-party-terms.md`), relative
URLs like `/privacy-policy` and `/acceptable-use-policies` caused error
-50 ("The application can't be opened") when clicked from installer
dialogs (such as the macOS installer).

This PR updates the relative URLs to absolute `https://zed.dev` URLs so
they open properly in the browser.
2026-08-17 09:35:54 +00:00
Arnesh da7d444cab google_ai: Add Gemini 3.7 Flash (#62670)
Follow-up to #62010, which added Gemini 3.6 Flash.

Google released Gemini 3.7 Flash on August 13, 2026. It keeps the 1
million token context window and the 64k output limit, and supports
thinking.

Unlike 3.5 and 3.6 Flash, it does not accept `thinking_level: MINIMAL`
(the API returns a validation error). So it exposes Low, Medium and
High, defaulting to Medium, and `disabled_thinking_level` in
`completion.rs` returns Low for it instead of Minimal when the user
turns thinking off.

The provider builds its model list from `google_ai::Model::iter()`, so
adding the enum variant is enough for it to show up in the model
dropdown.

Release Notes:

- Added Gemini 3.7 Flash to the Google AI models
2026-08-17 08:28:00 +00:00
Anant Goel 3d5fb8133a anthropic: Preserve request context during explicit compaction (#62745)
Explicit compaction currently removes tool definitions before sending
the request. That changes the prompt-cache prefix and can lower the
effective input size below Anthropic's minimum compaction trigger,
causing the request to complete without producing replacement context.

Keep tool definitions in explicit compaction requests while setting
`tool_choice` to `none`, preserving the input context without allowing
tool calls. Also append a user turn when the conversation ends with an
assistant message, since current Anthropic models reject that shape as
unsupported assistant prefill.

Testing:

- `cargo test -p anthropic`
- `cargo fmt --check`
- `./script/clippy -p anthropic`

Release Notes:

- N/A
2026-08-17 08:07:14 +00:00
Akihiro Okuno 74247e797e sidebar: Make project reordering key-bindable (#62695)
# Objective

- The sidebar already supports moving project groups through its **Move
Up** and **Move Down** context-menu entries, but those entries use
callbacks that cannot be referenced from `keymap.json`. Moving a project
several positions therefore requires reopening the menu for every step.
- Follow-up to #57448. Related to #61647.

## Solution

- Add `multi_workspace::MoveProjectUp` and
`multi_workspace::MoveProjectDown` actions. The handlers resolve the
active project group and delegate to the existing `MultiWorkspace`
reordering methods, keeping ordering and persistence behavior unchanged.
- Associate the actions with the existing context-menu entries so
configured shortcuts are shown alongside the menu commands. The menu
callbacks still operate on the project that was clicked.

## Testing

- Added a GPUI test that dispatches both actions and verifies that the
active project group moves in the expected direction and remains
unchanged at list boundaries:
- `cargo test -p workspace test_move_active_project_group_actions --
--nocapture`
- Manually verified on macOS with an isolated Zed user-data directory
and three project folders:
  - Assigned custom shortcuts to both actions in `keymap.json`.
  - Confirmed that the active project moves up and down in the sidebar.
- Ran formatting, compilation, and lint checks:
  - `cargo fmt --all -- --check`
  - `cargo check -p sidebar`
- `./script/clippy -p workspace -p sidebar -p gpui_platform --features
gpui_platform/runtime_shaders`

## Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

## Showcase

<details>
  <summary>Move projects with custom keybindings</summary>


https://github.com/user-attachments/assets/09432817-318b-484e-b630-a6012e9599cd

</details>

---

Release Notes:

- Sidebar: Added key-bindable actions for moving projects up and down.
2026-08-17 07:49:57 +00:00
Pavel Olizko 5b85565d93 gpui: Make inactive frame throttling configurable (#62628)
# Objective

I am building an [app](https://github.com/nolight132/sonora) with GPUI,
and the current animation throttling implementation does not quite meet
its requirements. I needed the window to stay at a smooth framerate when
unfocused to display lyrics, which was not possible at the time without
modifying GPUI’s frame scheduling behavior. I understand that this is
not a problem for Zed, but I believe making this behavior a field in
`WindowOptions` could be beneficial for other programs going forward.

## Solution

Added a field to `WindowOptions` struct which controls the minimum
interval between animation frames while the window is inactive
(documented). Kept the default value GPUI currently uses.

## Testing

- Ran `gpui/src/examples/animation.rs` with different presets - works as
expected. Zed compiles. One thing worth noting: this setting does not
guarantee the window refreshes at this exact interval, as frames are
still paced by the compositor. For granular FPS control, a helper
function is needed. I have decided to keep it simple and use the
existing logic.
- Tested on NixOS x86_64, Niri.

## 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 (the default didn't change,
tests still pass)
- [x] Performance impact has been considered and is acceptable (no
performance impact unless explicitly set)

## Showcase

Before (unfocused):
<img width="1280" height="802" alt="image"
src="https://github.com/user-attachments/assets/e3302c1d-4f4a-4503-96a2-0bf24e28096c"
/>

After (unfocused with `inactive_frame_interval` set to 16ms):
<img width="1450" height="972" alt="image"
src="https://github.com/user-attachments/assets/1183adf1-2da1-42d5-8e97-f4ad7a31b783"
/>

---

Release Notes:

- Added `WindowOptions::inactive_frame_interval` for configuring
animation frame throttling on inactive GPUI windows.
2026-08-17 07:20:20 +00:00
Darsh Poddar c772f94985 sidebar: Wrap import onboarding title when the panel is narrow (#62737)
Narrowing the agent sidebar clips the import-threads banner title
mid-word. The title now wraps instead of overflowing the close button.

<img width="212" height="279" alt="Screenshot 2026-08-16 at 11 25 26 PM"
src="https://github.com/user-attachments/assets/03e20b9d-ea29-4872-a4c1-f364509ddacb"
/>

Release Notes:

- Fixed the agent sidebar import-threads banner clipping its title when
the panel is narrow
2026-08-17 07:08:39 +00:00
Mikhail Butvin c984c41b54 project_panel: Make the window deactivation test actually deactivate (#62724)
Follow-up to #61852. The regression test I added there passes with or
without the fix.

The test creates the panel with `ProjectPanel::new` but never calls
`workspace.add_panel(...)`, so the panel is never rendered and its
filename editor never holds window focus. Deactivating the window then
blurs nothing, the project panel's `Blurred` handler never runs, and the
assertion holds trivially.

Add the panel to the workspace so it renders and its filename editor
takes focus, and assert that the editor is focused before deactivating,
so the test fails at an explanatory precondition rather than silently
going vacuous again.

Verified by running the new precondition without `add_panel`: it fails,
because the workspace's `on_focus_lost` fallback
(`crates/workspace/src/workspace.rs:1667`) reclaims focus from an editor
that was never rendered into the dispatch tree.

## Suggested .rules additions

> A GPUI test that depends on focus must put the view somewhere it can
actually be focused. Constructing a panel with `ProjectPanel::new` and
friends does not render it, so its editors never hold window focus and
every focus or blur assertion passes vacuously. Add it with
`workspace.add_panel(...)`, and assert the intended editor `is_focused`
before exercising blur.

Release Notes:

- N/A
2026-08-17 07:05:53 +00:00
Eric HolkandAnant Goel a3bf217dba Improve explicit compaction for Anthropic models (#62139)
Explicit compaction (`LanguageModel::compact`) was previously
implemented only for OpenAI-routed cloud models, which use a dedicated
compact operation proxied through `/completions/compact`. Anthropic
models only compacted automatically when a request's `compact_at_tokens`
trigger was crossed, leaving consumers without a provider-backed way to
request compaction immediately.

Anthropic has no compact-on-demand operation, but the `compact_20260112`
context-management edit provides the necessary pieces: the lowest
trigger the API accepts, 50,000 input tokens, combined with
`pause_after_compaction`, which stops the response after the compaction
block. Explicit compaction requests remove tools so the internal
summarizer must produce replacement context while retaining Anthropic's
default summarization prompt. The resulting readable summary, optional
opaque provider state, and usage are collected consistently.

This implements explicit compaction for both direct and hosted Anthropic
models. Hosted requests use the normal `/completions` endpoint; gateway
support for forwarding the compaction fields landed in
zed-industries/cloud#3216. Models expose the 50,000-token minimum so
callers can disable explicit compaction below the provider's floor.
Calls made below that floor still fail if the stream produces no
finalized compaction context.

The existing OpenAI compact operation is moved into a provider-specific
helper without changing its request, endpoint, response handling, or
provider-state ownership.

Testing:

- `cargo nextest run -p anthropic -p language_models_cloud -p
language_models`
- `./script/clippy -p anthropic -p language_model -p
language_models_cloud -p language_models`
- `cargo fmt --all --check`
- `git diff --check`

Release Notes:

- N/A

---------

Co-authored-by: Anant Goel <anant@zed.dev>
2026-08-17 04:27:38 +00:00
hvckandCole Miller 75c80abb31 git: Decode non-UTF-8 blobs for project diffs (#60821)
## Summary

Fixes #56449.
Related to #16965.

Zed’s Git panel and Project Diff build UI diffs from `language::Buffer`
diff bases loaded through the Git backend. Git blob loading previously
converted bytes with `String::from_utf8(...).ok()`, so legacy-encoded
blobs were treated as missing and the whole worktree file appeared newly
added.

This follows the same encoding path used for worktree buffers:

- move shared byte decoding and encoding into `language`
- keep Git blob, revision, and index APIs byte-oriented with `Vec<u8>`
- decode diff bases and index contents in `GitStore`, where
`language::Buffer`s are created
- encode index writes using the open buffer’s encoding and BOM so
partial staging does not rewrite the file as UTF-8
- keep worktree loading and saving on the same shared implementation

Regression coverage includes Windows-1251 decoding/encoding,
UTF-8/UTF-16 BOM preservation, raw Windows-1251 Git blob loading, and a
`BufferDiffSnapshot` assertion that a one-line CP1251 edit produces one
modified-line hunk instead of a full-file rewrite.

This does not run Git `textconv` commands. It fixes the reported
legacy-encoding case without executing repository-configured commands or
modifying working files on disk.

## Testing

- `cargo test -p language file_content::tests --locked`
- `cargo test -p git repository::tests::test_load_revisions --locked`
- `CARGO_INCREMENTAL=0 cargo test -p project
git_store::tests::test_decode_git_text_windows_1251_one_line_change
--locked`
- `CARGO_INCREMENTAL=0 cargo test -p project --test integration
test_restaging_hunk_after_optimistic_unstage --locked`
- `CARGO_INCREMENTAL=0 cargo check -p project --tests --locked`
- `CARGO_INCREMENTAL=0 cargo check -p git_ui --tests --locked`
- `cargo fmt --all --check`
- `git diff --check`

## Suggested .rules additions

- N/A

Release Notes:

- Fixed Git panel and Project Diff rendering for legacy-encoded text
files whose Git blobs are not valid UTF-8.

---------

Co-authored-by: Cole Miller <cole@zed.dev>
2026-08-17 01:47:11 +00:00
Anant Goel 8ecd20779c openai_subscribed: Request ungated account model catalog (#62729)
The ChatGPT Codex models endpoint interprets `client_version` as a Codex
CLI compatibility version and filters models whose
`minimal_client_version` is newer. Zed was passing its unrelated
application version, so catalog contents depended accidentally on how
Zed's release number compared with Codex's version sequence.

A read-only sweep against the authenticated endpoint showed that
omitting the parameter returns HTTP 400, ordinary versions receive the
expected compatibility-filtered subsets, and `0.0.0` is a special
ungated sentinel. The `0.0.0` response had the same model set, ETag, and
canonical body hash as current and higher Codex versions, while `0.0.1`
returned no models.

This moves ownership of that behavior into `openai_subscribed::State`.
The normal constructor now always requests the ungated account catalog,
and the public constructor that accepted arbitrary host versions is
removed so applications cannot accidentally couple model visibility to
their own version scheme. The existing initial-load test pins the
resulting `client_version=0.0.0` request.

Testing performed:

- `cargo nextest run -p openai_subscribed`
- `cargo nextest run -p language_models openai_subscribed`
- `./script/clippy -p openai_subscribed -p language_models`
- `cargo fmt --all -- --check`
- `git diff --check`

Release Notes:

- Fixed ChatGPT subscription model discovery to avoid filtering models
by Zed's application version.
2026-08-17 00:54:13 +00:00
kirim 9093ccd5d5 Recognize .brushrc files as shell scripts (#62720)
Add `.brushrc` to the Shell Script language configuration so
[Brush](https://github.com/reubeno/brush) shell configuration files
receive shell syntax highlighting.

Release Notes:
- Added Shell Script language detection for `.brushrc` files.
2026-08-17 00:36:13 +00:00
Ethan Williams d2bbf4a835 agent: Add ask_user tool using elicitation forms (#61497)
## Summary

Adds a first-party `ask_user` tool to Zed's native agent
(`crates/agent`) that lets the agent ask the user a question and get an
answer back through a proper **elicitation form** rather than free-form
chat text.

This is a step towards the interactive-question experience requested in
[discussion
#48784](https://github.com/zed-industries/zed/discussions/48784)
(implement the ACP elicitation spec for agent questions). Zed already
renders elicitation forms client-side; this wires the native agent up to
that existing rail so the agent can drive single-select and/or free-text
prompts.

## What it does

The tool takes:

- `question` — the prompt shown to the user
- `options` — optional list of selectable choices (single-select)
- `allow_free_text` — whether the user may type a custom answer instead
of picking an option

The agent decides the shape of each question:

| `options` | `allow_free_text` | Result |
| --- | --- | --- |
| 2+ | `false` | Single-select only |
| 2+ | `true` | Single-select with a free-text "other" field |
| empty | `true` | Free-text only |

A typed answer takes precedence over a selected option, and the tool
always resolves (a cancelled or failed elicitation is reported back to
the agent rather than hanging).

## Demo



https://github.com/user-attachments/assets/9d438d87-af65-4fa2-b500-b1232007d0a0


## Implementation

- `thread.rs` — new `ThreadEvent::Elicitation(ElicitationRequest)`
variant plus `ToolCallEventStream::request_elicitation`, mirroring the
existing `prompt_for_decision` permission rail.
- `agent.rs` — handles the elicitation event by building a
session-scoped `acp::CreateElicitationRequest` and routing it through
`AcpThread::request_elicitation`, piping the response back to the tool.
- `tools/ask_user_tool.rs` — the tool itself, including schema
construction and response extraction.
- Registered in the `write` and `ask` profiles and excluded from the
tool-permissions setup UI.

No client-side UI changes were needed — the existing elicitation form
rendering handles it.

## Tests

`cargo test -p agent ask_user` — 5 unit tests covering schema
construction, validation, and accept/decline/cancel handling.

Release Notes:

- Added an `ask_user` tool that lets the agent ask the user a question
with selectable options and/or free-text input, rendered as an
elicitation form
2026-08-17 00:36:02 +00:00
Tai NguyenandCole Miller 8fd8efd105 git_ui: Fix Trash Untracked Files with many files (#61602)
Release Notes:

- Fixed Trash Untracked Files bailing out early with many selected files
when trashing one file failed.

---------

Co-authored-by: Cole Miller <cole@zed.dev>
2026-08-16 23:19:39 +00:00
Kirill Bulatov 468837a78d Merge array settings from extension contributions instead of overwriting (#62686)
Closes https://github.com/zed-industries/zed/issues/62572

Reworks https://github.com/zed-industries/zed/pull/54950 — instead of
unconditionally replacing the array with a different one, now does the
replacement only when the user settings are set.
The rest now merges into the array.


Release Notes:

- Fixed array merging for extensions case
2026-08-16 21:10:59 +00:00
Kirill Bulatov 3a21e04379 Fixed the zoomed agent panel closing unexpectedly on rewind (#62711)
`ThreadView::regenerate` does `thread.rewind()` which de-focused the
message editor mid-flight causing the zoomed panel to disappear.

* workspace: Keep zoomed panels open when window focus is lost

Commit adds a test + tweaks a default, generic, fallback to be more
lenient: instead of focusing the workspace (and hiding all panels right
away), try to fall back to whatever panel open

* gpui: Restore focus to nearest surviving ancestor when focus is lost

Commit tries to push it down to a library level and add a way to fall
back to closest ancestor that's still visible with the focus instead.


Release Notes:

- Fixed the zoomed agent panel closing unexpectedly on rewind
2026-08-16 14:42:24 +00:00
Finn Evers aab84dab21 editor: Match invisible character ranges directly (#62708)
Local benchmark shows this speeds it up by at least 30% and is
definitely more reasonable to have like this than compared to iterating
over a list for every given char.

Release Notes:

- N/A
2026-08-16 13:40:29 +00:00
895f438c1a editor: Fix buffer header context menu line height in multibuffers (#61923)
## Objective

Right-clicking a buffer header in a multibuffer showed a context menu
whose item spacing did not match other context menus. The menu is drawn
via a deferred draw, which inherits the editor's text style stack, so
its line height followed `buffer_line_height` instead of the default UI
line height.

This is the same root cause as #24504, which #25172 fixed for the
editor's mouse context menu and completion popovers. The buffer header
menu was a remaining call site.

## Solution

`ContextMenu` now applies the default (`comfortable`) line height itself
in `render`, next to its existing rem size and font family
normalization, so menus render the same regardless of where they are
opened from. This fixes the all workarounds and the need for them too:
the workaround in `layout_mouse_context_menu` is removed, and the buffer
header ends up needing no changes at all.

The completions and code actions popovers keep their override in
`element.rs`: they are not `ui::ContextMenu`s and compute their sizes
with eager `window.line_height()` reads while being built, so styling on
the elements they return cannot cover them. Migrating them could be a
follow-up.

## Testing

- `cargo check --workspace` passes, `./script/clippy` on the touched
crates passes.
- Manual: set `"buffer_line_height": "standard"` (or any extreme custom
value to see it better), open a multibuffer (e.g. project search),
right-click a buffer header, and compare the menu with another context
menu (e.g. a tab's) — spacing matches. The editor's mouse context menu,
which lost its own override, renders as before, and with default
settings there is no visual change anywhere.
- Tested on macOS, change is platform-independent styling.

## 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 (visual styling fix; menu
text styles have no existing test coverage)
- [x] Performance impact has been considered and is acceptable

## Showcase

Regular context menu:
<img width="425" height="164" alt="A context menu elsewhere in the app,
showing normal item spacing"
src="https://github.com/user-attachments/assets/1fc13981-b394-444f-883a-ce3ef462c386"
/>

Before:
<img width="425" height="164" alt="Buffer header context menu before the
fix, with tighter item spacing following the custom buffer_line_height"
src="https://github.com/user-attachments/assets/9774076c-7e0c-41dd-b54f-53de58b24336"
/>

After:
<img width="425" height="164" alt="Buffer header context menu after the
fix, with item spacing matching other context menus"
src="https://github.com/user-attachments/assets/ae76e37c-8e39-474c-8a5e-e229e69173fb"
/>

---

Release Notes:

- Fixed the file header context menu in multibuffers not matching other
context menus' spacing when a custom `buffer_line_height` is set.

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>
2026-08-16 11:41:17 +00:00
ArneshandFinn Evers b99ce02038 repl: Save notebooks through the project instead of the local filesystem (#62602)
Closes #59001

Saving a notebook wrote the file with
`project.fs().atomic_write(abs_path, ...)`. `Project::fs()` is always
the client's own filesystem, so for a remote project the remote path was
resolved against the local machine: on Windows the drive letter got
prepended and the atomic-write temp file used a backslash, producing
`C:/data/project/src_example\.tmpPuzw3d3` and `os error 3`. The same
thing fails on macOS/Linux clients with `os error 2`.

Both `save` and `save_as` now go through the project's buffer machinery
instead: open the buffer for the notebook's `ProjectPath`, set its text
to the serialized notebook, then `save_buffer` / `save_buffer_as`.
Writes are routed over the remote connection for remote projects, and
the open buffer stays in sync locally.

`save_as` also updates the item's project path and entry id, since
`save_buffer_as` moves the buffer to the new path and otherwise the next
save would write back to the old file.

Added a test that edits a cell, saves, and checks that the notebook
buffer held by the project reflects the saved file. It fails against the
old implementation.

Release Notes:

- N/A

---------

Co-authored-by: Finn Evers <finn.evers@outlook.de>
2026-08-15 19:55:10 +00:00
Kirill Bulatov 20a95914df Remove the problematic data field from the snapshot (#62685)
Follow-up to https://github.com/zed-industries/zed/pull/62658

The problematic field is not needed at all in the snapshot, as can be
constructed before starting the scanner — moreover, the field had
accumulated more and more paths between rescans, leaking memory.

Now, we spend more time traversing the entire tree between rescans, but
that happens for rescans only which should be relatively rare?

Release Notes:

- N/A
2026-08-15 19:31:04 +00:00
Caio Raphael bd1a4abe26 title_bar: Fix test-support feature mismatch (#62284)
Follow-up to #46337, same fix as #48280.

`title_bar` tests enable `remote/test-support`, which adds
`RemoteConnectionOptions::Mock`. But without
`recent_projects/test-support`, the match arms for that variant aren't
compiled, causing a non-exhaustive match error when testing the crate in
isolation:

```
error[E0004]: non-exhaustive patterns: `&RemoteConnectionOptions::Mock(_)` not covered
    --> crates/remote_connection/src/remote_connection.rs:233:76
```

CI doesn't catch this because `collab` and `sidebar` enable
`recent_projects/test-support` during workspace-wide tests.

Adding `remote_connection/test-support` instead isn't enough — that just
moves the same error into `recent_projects`.
`recent_projects/test-support` covers both.

Release Notes:

- N/A
2026-08-15 19:00:20 +00:00
AbdAlRahman Gad 437fe0f797 git_ui: prevent branch name overflow in git details pane (#62665)
# Objective

- prevent branch name overflow in git details pane
- Fixes #62526 

## Solution

- set min width
- add tooltip for readability

## Testing

- manual testing

## 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
### before
- 
<img width="670" height="205" alt="image"
src="https://github.com/user-attachments/assets/26716b50-6f09-40c1-bec5-d78bd913d4ec"
/>

- No tooltip

### After
- 
<img width="499" height="203" alt="image"
src="https://github.com/user-attachments/assets/3eee21e8-f9e8-4c30-a21d-0c23bf25c9de"
/>

- Tooltip: 

<img width="609" height="364" alt="image"
src="https://github.com/user-attachments/assets/822d784d-889e-4d26-b8e6-de46f8206569"
/>

---

Release Notes:

- N/A or Added/Fixed/Improved ...
2026-08-15 15:13:04 +00:00
Ali abacaae1cd Make search much faster (#62658)
# Objective

Project search sends one candidate per file to its worker pool, and each
one
carried an owned `Snapshot`. Every field of `Snapshot` is cheap to clone
except
`always_included_entries`, a `Vec<Arc<RelPath>>` holding one entry per
always-included file.

With a broad file_scan_inclusions such as **/*, that vector holds an
entry per file in the project, so cloning it once per file made search
O(files²).

Partially addresses #38799 (still needs to fix the huge memory usage and
the occasional stutters) .

## Solution

Share the snapshot behind an `Arc` instead, the consumer only reads
`id()`, `abs_path()`
and `root_name()`, so nothing needs an owned copy.

## Testing
Using the [linux kernel repo](https://github.com/torvalds/linux), i
searched for `vmx_l1d_should_flush
` and `netif_rx` and its at least 60x faster on 5950x. 
with `file_scan_inclusions: ["**/*"]`


Release Notes:

- Fixed project search being very slow on projects that set a broad
`file_scan_inclusions`
2026-08-15 14:09:29 +00:00
Kunall Banerjee 4155155572 acp: Poll the client connection future on a dedicated thread (#62259)
Some context behind this change: I’ve been meaning to look into this
because I kept running into this crash when working on
[other](https://github.com/zed-industries/zed/issues/61040) fixes.
Everything worked fine in dev builds, right up until you tried to create
a new Agent Thread using an ACP adapter. The crash reports in this
instance were throwing me off: I was seeing different things each time.

So, I had Fable look into this. It did so by binary-searching the
minimum thread stack on which a probe replicating Zed’s exact handler
chain can dispatch one message. Full methodology, probe source, and raw
numbers can be found in [this
gist](https://gist.github.com/yeskunall/2ac2b00f51389d9388d607974f6f8a04).
The results of the probe are as follows:

| SDK | Minimum stack (dev profile) | vs. 512 KiB GCD budget |
|---|---|---|
| 1.3.0 | 409,600–413,696 B | fit, ~100 KiB headroom |
| 2.0.0 | 507,904–512,000 B | entire budget before runtime overhead |

The oversized frames are monomorphized into `agent_servers`, not the SDK
crate -- a `[profile.dev.package]` opt-level override on
`agent-client-protocol` does **not** fix this (see gist), and optimized
builds collapse the frames entirely, which is why only dev builds
crashed. It found that the real signature is `fault_address ==
stack_pointer` on a `com.apple.root.default-qos` thread inside the ACP
dispatch specialization, which I then had it verify across six local
`.ips` reports. It seems in #61570, we pushed the dispatch chain past
the GCD budget, explained further below:

`AcpConnection::stdio` polled the ACP client connection future via
`background_spawn`, which on macOS executes runnables on
[GCD’s](https://developer.apple.com/documentation/DISPATCH) global-queue
workers. Those threads have kernel-fixed, unconfigurable [512 KiB
stacks](https://github.com/apple-oss-distributions/libpthread/blob/42d026df5b07825070f60134b980a1ec2552dfee/kern/kern_internal.h#L154).
In unoptimized builds, the SDK’s chained-handler dispatch needs **~0.5
MiB of stack per inbound message** (again, see linked gist), so the
first message overflows the guard page and takes the process down.

Therefore, this 512 KiB constraint is **macOS-only**. Linux doesn’t use
GCD -- GPUI [spawns its own `std::thread`
workers](https://github.com/zed-industries/zed/blob/2ade98f6a9320b9c7d6e65398fc4c364c367c1bd/crates/gpui_linux/src/linux/dispatcher.rs#L39)
([2 MiB Rust
default](https://github.com/rust-lang/rust/blob/59807616e1fa2540724bfbac14d7976d7e4a3860/library/std/src/sys/thread/unix.rs#L26)).
Windows uses [the OS thread
pool](https://github.com/zed-industries/zed/blob/2ade98f6a9320b9c7d6e65398fc4c364c367c1bd/crates/gpui_windows/src/dispatcher.rs#L68),
which [inherits the executable’s stack
reserve](https://github.com/MicrosoftDocs/sdk-api/blob/4502fff176b3b56beddb6a63c9f980377b11ba9b/sdk-api-src/content/threadpoolapiset/nf-threadpoolapiset-setthreadpoolstackinformation.md?plain=1#L58)
-- [1 MB linker
default](https://github.com/MicrosoftDocs/win32/blob/2eb6588c6703d31599285bbb06563c3d41b57590/desktop-src/ProcThread/thread-stack-size.md?plain=1#L17),
but Zed already bumps it to 8 MiB in
[crates/zed/build.rs:88](https://github.com/zed-industries/zed/blob/2ade98f6a9320b9c7d6e65398fc4c364c367c1bd/crates/zed/build.rs#L88)
(see [TODO
comment](https://github.com/zed-industries/zed/blob/2ade98f6a9320b9c7d6e65398fc4c364c367c1bd/crates/zed/build.rs#L87)).

---

Release Notes:

- N/A
2026-08-15 00:30:00 +00:00
Anant GoelandEric Holk bb1adf9781 agent: Share compatible Chat Completions infrastructure (#62652)
OpenAI-compatible providers currently cannot reuse Zed's OpenAI Chat
Completions transport unless they also adopt the exact OpenAI request
and response types. OpenRouter therefore maintained its own copy of
request construction, authentication, status handling, response reading,
and server-sent event framing.

This change extracts that mechanical transport into two provider-neutral
functions in `open_ai`: one for streaming requests and one for
non-streaming requests. They accept any serializable request envelope,
preserve custom headers and provider names, return untyped JSON for
provider-specific decoding, and retain typed failures for serialization,
request construction, HTTP transport, response reading, and
deserialization. The existing OpenAI entry points remain as
compatibility wrappers, so existing callers keep the same API and
behavior.

The abstraction deliberately stops at the wire boundary. OpenRouter
continues to own its request and response schemas, attribution headers,
routing controls, cache placement, and API-specific error
interpretation. It now adapts the shared framed stream into those
OpenRouter types instead of implementing a second HTTP and server-sent
event stack.

Moving OpenRouter onto the shared path also requires the ordinary Chat
Completions schema and event mapper to preserve compatible metadata that
OpenRouter already emits. This includes structured reasoning details
needed for replay, fragmented reasoning accumulation, prompt-cache read
and write usage, and thought signatures attached to tool calls. The
stream exposes `[DONE]` explicitly rather than treating it as
indistinguishable from an unexpected end of the response body.
OpenRouter's routing session identifier is hashed before transmission so
Zed's internal thread identifier is not exposed.

The diff is larger than the extracted transport alone because the shared
API is additive, the compatibility metadata must be represented in the
common wire types and event mapper, and the provider-specific adapter
remains intentionally independent. Roughly four hundred added lines are
focused transport, metadata, error-classification, attribution, caching,
and privacy tests. The provider-level OpenRouter implementation becomes
smaller while preserving its existing behavior.

Testing performed:

- `cargo test -p open_ai`
- `cargo test -p open_router`
- `cargo nextest run -p language_models open_router`
- `cargo check -p edit_prediction -p edit_prediction_cli`
- `cargo fmt --all -- --check`
- `./script/clippy -p open_ai -p open_router -p language_models -p
edit_prediction_cli`
- `cargo machete`

Release Notes:

- Improved OpenRouter reasoning continuity and request privacy.

---------

Co-authored-by: Eric Holk <eric@zed.dev>
2026-08-14 22:42:27 +00:00
Anant Goel 9b05e122be openai_subscribed: Discover account-specific models (#62651)
ChatGPT subscription model availability is determined by the
authenticated Codex backend and can vary by account. The provider
currently exposes a bundled static list and defaults to GPT-5.6 Sol, so
users can be offered a model that their ChatGPT account subsequently
rejects.

This change fetches the account-scoped Codex model catalog after loading
stored credentials and after sign-in. Requests use the existing OAuth
token, ChatGPT account ID, Zed originator, and the Zed client version.
Picker-visible models are ordered by the server's priority, and the
returned metadata drives model names, context windows, image support,
reasoning levels, and Fast Mode support.

The bundled list remains available before discovery and when discovery
fails. A failed refresh preserves the last usable catalog and surfaces
the failure in provider settings, while generation checks prevent a
response for an older account or request from replacing newer state.
Model discovery uses the same five-second timeout as Codex so a stalled
catalog endpoint cannot indefinitely delay authentication. Zed's
language model provider now derives its provided, default, recommended,
and fast models from that resolved catalog.

Testing performed:

- `cargo nextest run -p openai_subscribed`
- `cargo nextest run -p language_models`
- `./script/clippy -p openai_subscribed -p language_models --lib`
- `cargo fmt --all -- --check`
- `git diff --check`

Release Notes:

- Fixed ChatGPT subscription accounts offering models that are not
available to them.
2026-08-14 20:44:17 +00:00
Kirill Bulatov c1dab7a0d3 Support blaming parent revisions (#62614)
Closes https://github.com/zed-industries/zed/discussions/42583

Adds more tooltip entries and `editor::BlameRevision`,
`editor::BlamePreviousRevision` actions to use.
Started to highlight gutter blame entries that belong to currently
annotated commit.


https://github.com/user-attachments/assets/ba754e0b-6431-407c-8d79-2f8b0324fde1


Release Notes:

- Supported blaming parent revisions
2026-08-14 20:24:13 +00:00
Anthony Eid 232eaba704 Extract shared Apple renderer from gpui_macos (#62649)
Extract parts of `platform_macos` to `gpui_apple` to be used as a shared
crate between `gpui_macos` and a future `gpui_ios` for iOS/iPadOS apps.

Release Notes:

- N/A
2026-08-14 19:53:25 +00:00
Anthony Eidandzed-zippy[bot] a55d40ac62 gpui: Unify performance tracking under the profiler feature (#62496)
GPUI currently splits performance instrumentation across several Cargo
features and runtime controls. Task profiling, frame-duration
histograms, input-latency histograms, and benchmark frame timing
therefore follow separate code paths despite measuring related parts of
the same UI work.

This PR consolidates those systems under the `profiler` Cargo feature.
The `bench` feature now enables `profiler`, aggregate frame and
input-latency histograms remain active whenever profiling is compiled
in, and `set_trace_enabled` controls whether individual task timings and
per-frame draw and presentation records are retained.

The change also introduces a single per-window profiler that owns the
begin and end state for input dispatch, drawing, and presentation, and
routes window action-handler timing through the existing aggregate
action tracker. Draw and presentation records reuse the same timestamps
and computed intervals as the aggregate histograms, avoiding duplicate
clock reads. Benchmark trace scopes are reference-counted so overlapping
measurements cannot disable tracing while another measurement still
needs it.

This does not change hang detection directly. It establishes the common
profiling foundation needed to correlate slow or delayed frames with
actions and foreground or background tasks. Better attribution should
make it easier to find and prevent responsiveness regressions.

Release Notes:

- N/A

---------

Co-authored-by: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>
2026-08-14 16:33:25 +00:00
Oleksandr Kholiavko f65b8464f6 csv_preview: Evolve into tabular data preview (#60768)
# Objective

The MVP version of CSV preview is ready. However it's trivial to extend
it to TSV & other formats.

## Solution

This PR does exactly that - switching from CSV only to any tabular data
(TSV/CSV/PSV/SSV).
1. added `tsv`/`psv`/`ssv` support
2. renamed action/eye button & crate
3. added `.psv`/`.ssv` types to use database icon (similar to
`csv`/`tsv`)
2. Added `Table` svg icon (was previously missing) so preview is not
longer using book icon (from markdown preview).

> NOTE: Crate renaming will be done separately (as it's mechanical work
& I don't want to mix it with logic changes)

## Testing

Opened csv/tsv/psv/ssv files in peview

## 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

PSV/SSV file formats icon

| Before | After |
| --- | --- |
| <img width="141" height="136" alt="image"
src="https://github.com/user-attachments/assets/ff5ec1a2-10e3-4363-a467-d535c7f621c0"
/> | <img width="143" height="135" alt="image"
src="https://github.com/user-attachments/assets/f4a85276-beee-4d3e-bc59-319c4fc8812c"
/> |

Change namespace for actions (`csv` -> `tabular data`)

| Before | After |
| --- | --- |
| <img width="551" height="150" alt="image"
src="https://github.com/user-attachments/assets/f7b79a7f-b300-4d14-8565-b42b3bcb11c4"
/> | <img width="558" height="152" alt="image"
src="https://github.com/user-attachments/assets/be9dcc54-51a4-4736-9539-172fecabdf6d"
/> |


Update parser & detection logic to support preview for TSV/PSV/SSV

| Before | After |
| --- | --- |
| <img width="470" height="287" alt="image"
src="https://github.com/user-attachments/assets/d0222bd1-91a7-46e0-b4da-76be0642bf51"
/> | <img width="541" height="275" alt="image"
src="https://github.com/user-attachments/assets/3c4d237a-4956-46ad-b7d6-3a8782b41888"
/> |


Introduce table svg icon

| Before | After |
| --- | --- |
| <img width="349" height="66" alt="image"
src="https://github.com/user-attachments/assets/bd7999ef-516f-43d1-a0e6-50055c1c3bed"
/> | <img width="331" height="50" alt="image"
src="https://github.com/user-attachments/assets/fc534921-0c15-421c-b046-8c5967178d24"
/> |


---

Release Notes:

- N/A or Added/Fixed/Improved ...
2026-08-14 15:58:14 +00:00
Bennet Bo Fenner a5234566b4 editor: Treat blank rename as no-op (#62630)
Confirming an inline rename after deleting the entire symbol name or
entering only whitespace currently submits an invalid rename request to
the language server. This can remove the symbol text instead of leaving
the source unchanged.

Treat empty and whitespace-only replacements as successful no-ops after
dismissing the inline rename UI. Returning a completed task also
consumes the confirmation action, preventing Enter from propagating back
into the editor. Non-blank rename behavior remains unchanged.

The regression test covers both empty and whitespace-only rename fields,
verifying that no LSP rename request is sent and the original buffer
remains intact.

Release Notes:

- editor: Fixed confirming a blank symbol LSP-rename modifying the
source code
2026-08-14 13:53:21 +00:00
f7356481e7 JetBrains keymap: Add CamelHump subword navigation (#51540)
Closes #21054

## Summary
• make the JetBrains base keymap use subword motions for
`Alt+Left/Right` and `Shift+Alt+Left/Right` in editors
• keep Zed's default keymaps and the underlying `word`/`subword`
primitives unchanged
 • document word vs. subword navigation in the key bindings docs
• document the JetBrains default in the IntelliJ, WebStorm, PyCharm, and
RustRover migration guides

## Testing
 • `./script/check-keymaps`
 • `cargo fmt --all -- --check`
 • `./script/clippy -p editor`
• `cd docs && pnpm dlx prettier@3.5.0 src/key-bindings.md
src/migrate/intellij.md src/migrate/webstorm.md src/migrate/pycharm.md
src/migrate/rustrover.md --check`

Related to #12816 and #34090, but does not actually address the
configurable word separators or broader subword semantics. Intentionally
scoped to JetBrains keymap defaults & docs.

Release Notes:

- Improved JetBrains keymap behavior by adding CamelHump-style subword
navigation in editors.

---------

Co-authored-by: Tom Houlé <tom@tomhoule.com>
Co-authored-by: Antonio Scandurra <me@as-cii.com>
2026-08-14 12:31:48 +00:00