Commit Graph
39175 Commits
Author SHA1 Message Date
Ben Brandt 46a64b17b5 acp: Validate registry agent checksums (#61334)
The registry now has optional checksums that we can use.

Release Notes:

- N/A
2026-07-20 13:21:18 +00:00
Finn Evers 3e78d2068e icons: Add test to ensure all icon variants exist (#61337)
This is just to help with bookkeeping, as we currently do not ensure
anywhere icons do actually exist.

Release Notes:

- N/A
2026-07-20 12:48:40 +00:00
Jakub Konkaandapoorva-01 913a81546d workspace: Fix crash when closing active item mid-update (#61336)
Closes https://github.com/zed-industries/zed/issues/61182

Supersedes https://github.com/zed-industries/zed/pull/61232

Closes FR-128

Release Notes:

- Fixed crash when closing active item while the workspace was
mid-update (double-lease panic).

Co-authored-by: apoorva-01 <vermaapoorva0510@gmail.com>
2026-07-20 12:39:07 +00:00
Venkatesh R b660cf8e0e snippet: Preserve escaped characters in non-default choice options (#61313)
Closes #61312

In `parse_choices`, the escape branch only appended the escaped
character to `current_choice` when parsing the first choice, because the
push was placed inside the `!found_default_choice` guard. That guard is
only meant for `text` (the default value inserted into the buffer) — the
plain-text branch below handles it that way. As a result, `${1|a,b\,c|}`
offered the choices `a` and `bc` instead of `a` and `b,c`, and the same
applied to any `\,`, `\|`, or `\\` in choices after the first.

Moved `current_choice.push(c)` out of the guard and added a regression
test covering escaped comma, pipe, and backslash in non-first choices.
Escapes in the first choice were already covered by the existing test
and are unchanged.

Before / after (snippet body `"${1|a,b\\,c|}"`): the choice dropdown
showed `a` / `bc`, now shows `a` / `b,c`.

Release Notes:

- Fixed escaped characters (`\,`, `\|`, `\\`) being dropped from snippet
choice options after the first one
2026-07-20 11:17:43 +00:00
Danilo Leal e1ee74dcbf worktree_picker: Improve discoverability of tasks as a creation setup mechanism (#61148)
Sometimes when creating Git worktrees, it's necessary to set things up
so the new worktree is ready. For example, copying env.vars, installing
dependencies, etc. That was already possible in Zed through the tasks
system, but you'd only maybe know about that if you read the
documentation or is super familiar with it already; nothing in the
product in the context of worktrees told you about that. This is what
this PR does.

Now, in the worktree picker, there's a "" button that opens the
`tasks.json` file exposing the `create_worktree` hook, which allows you
to plugin all sorts of things to be run by the time of a worktree
creation. If you don't already have a `tasks.json` file, we will create
a new one for you with a worktree-creation template. Otherwise, we
either append the `create_worktree` hook content to it or just open the
file.

Here's a quick video:


https://github.com/user-attachments/assets/21908be4-306b-4cf3-bed0-50d52cad9d79

Release Notes:

- Git Worktrees: Improved discoverability of the `create_worktree` hook
for setting up things that need to happen by the time of worktree
creation.
2026-07-20 11:17:21 +00:00
Agani Daniel .SandSmit Barmase a77838bb98 workspace: Rename "Discard" to "Discard Edits" in file conflict prompt (#55870)
When a file has unsaved edits and has also changed on disk, the conflict
prompt offered "Overwrite / Discard / Cancel". Both "Overwrite" and
"Discard" were directionally ambiguous, it wasn't clear whether the disk
contents or the buffer edits would be lost. "Discard Edits" makes it
explicit that the buffer edits are thrown away and the disk version is
reloaded.

Release Notes:

- Improved the file conflict prompt by renaming the "Discard" button to
"Discard Edits" to clarify that unsaved edits are discarded in favor of
the on-disk contents.

---------

Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com>
2026-07-20 06:58:37 +00:00
Warya Wayne 4eb6383ad8 markdown_preview: Show link destinations on hover (#60942)
# Objective

Markdown Preview does not reveal where a link will navigate before it is
opened or right clicked to copy the URL.

Show a small Firefox-style URL preview in the bottom-left corner when
hovering text links or linked images.

## Solution

- Added URL hover reporting to the Markdown renderer, including hit
detection for linked images that are outside the text layout.
- Used the existing `LinkPreview` component to display the hovered
destination in the bottom-left corner of the Markdown preview.
- Cleared the destination preview when the pointer leaves a link, the
preview, or the displayed Markdown changes.

## Testing

- Confirmed the project builds successfully and manually verified the
behavior on macOS.
- Hovered text links and linked images in a Markdown preview and
confirmed their destinations appear in the bottom-left corner.
- Moved the pointer away from links and outside the preview and
confirmed the destination preview disappears.
- Reviewers can test this by opening a Markdown file containing a text
link and a linked image, opening its preview, and hovering each link.

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

## Showcase

See bottom left of this image for a sample of the link preview in
action.

<img width="2240" height="1258"
alt="warya_wayne_fix_markdown_render_link_preview_zed_pr"
src="https://github.com/user-attachments/assets/7659e2ae-161d-4a41-a5b4-ba5b76951e30"
/>


---

Release Notes:

- Improved Markdown previews by showing link destinations in the
bottom-left corner when hovering links.
2026-07-20 05:47:22 +00:00
Apoorva Verma 166e52d76f terminal: Don't steal focus from an open modal on background terminal startup (#60960)
the startup terminal can take a sec to come up if your shell is slow.
when it's ready it grabs focus, and if you've opened the command palette
by then, that blurs the palette input and closes it. so it just
vanishes.

`add_center_terminal` focused the new terminal unconditionally. now it
skips the focus if a modal is open (`!has_active_modal`). one line at
the definition, covers all the call sites.

kept it terminal-specific like dinocosta framed it. could do a broader
workspace-level "don't steal from a modal" instead if you'd prefer.

two tests: modal stays focused after a background terminal spawns (fails
without the fix), and no-modal still focuses the terminal like before.

Fixes #60762.

Release Notes:

- Fixed a background terminal finishing startup closing the command
palette or an open picker
2026-07-20 05:42:44 +00:00
saberoueslatiandChris Biscardi 7113882745 git_ui: Restore search in solo diff views (#60936)
## Context

Buffer search did not work in file diffs opened from the Git panel
because `SoloDiffView` did not expose its embedded editor as searchable.
Restoring search also revealed that the primary toolbar clipped several
search controls, so the deployed search bar now uses the full-width
secondary row for this view.

Closes #60659.

## How to Review

Three files changed. Read in this order:

**`crates/git_ui/src/solo_diff_view.rs`** :
`SoloDiffView::as_searchable` now returns its embedded
`SplittableEditor`, restoring search for the focused diff side while
keeping the editor hidden from global diff-style controls.

**`crates/search/src/buffer_search.rs`** : Buffer search now detects
when its searchable split editor is intentionally hidden by the
containing item. When deployed, this case uses the secondary toolbar row
so Toggle Replace, search options, match navigation, and match counts
remain visible. Other multibuffer layouts keep their existing primary
toolbar location.

**`crates/git_ui/src/git_panel.rs`** : The regression test now opens a
solo diff through the Git panel, confirms the split editor is
searchable, deploys buffer search, verifies the secondary toolbar
location, runs a query, and checks that the focused editor receives a
search highlight.

Manual test after the fix below :

[Screencast from 2026-07-14
00-39-04.webm](https://github.com/user-attachments/assets/022ab106-d35a-4a75-98db-8809b86fa58d)

## Self-Review Checklist

- [x] I've reviewed my own diff for quality, security, and reliability
- [ ] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the UI/UX checklist
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

Release Notes:

- Fixed searching in file diffs opened from the Git panel.

Co-authored-by: Chris Biscardi <chris@christopherbiscardi.com>
2026-07-20 05:37:29 +00:00
Baris Palaska c2a36f2945 gpui_web: Only cancel the native context menu when the app claims the right-click (#60892)
# Objective

The contextmenu listener cancelled the browser's native menu
unconditionally, so pages hosting a gpui app lost right-click entirely
wherever the app showed no menu of its own, and apps that do show one
had no native menu to suppress selectively.

## Solution

Record whether the right-button MouseDown dispatch was consumed (a
handler called stop_propagation, e.g. to open a custom menu) and cancel
the native menu only in that case: app menus win where they exist, the
browser menu everywhere else. Apps opening custom context menus should
mark the triggering mousedown consumed to opt in.

## Testing

Tested locally

## Self-Review Checklist:

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

## Showcase

<img width="816" height="288" alt="context menu"
src="https://github.com/user-attachments/assets/c79cd2ef-d465-4431-8461-7a9feb922576"
/>


Release Notes:

- N/A
2026-07-20 05:31:27 +00:00
Apoorva Verma 60dff45e08 terminal: Start a selection on shift+drag when mouse tracking is active (#60880)
run htop or btm and you can't select terminal text with shift+drag, the
usual escape hatch does nothing.

#25143 made shift+click only ever extend a selection, never start one.
so with nothing selected there's no anchor and the drag has nothing to
grab. now it drops an anchor when there's no selection, and still
extends when there is.

added two event-level tests (harness can't sync without a window):
shift+drag under mouse tracking, which fails without the fix, and
shift+click still extending.

Fixes #60254.

Release Notes:

- Fixed Shift+click-drag not selecting terminal text while an app has
mouse tracking enabled
2026-07-20 05:29:27 +00:00
ᴀᴍᴛᴏᴀᴇʀandMax Stevens a98c7e2fa8 editor: Add language detection for untitled buffers (#61201)
# Objective

Closes #4868.

Untitled buffers start as Plain Text and require users to select a
language manually before receiving syntax highlighting. Add lightweight
automatic language detection for code entered or pasted into untitled
buffers.

## Solution

This builds on [Max Stevens's earlier language-detection
work](https://github.com/zed-industries/zed/pull/43057), replacing
Magika with [Betlang](https://github.com/DioxusLabs/betlang).

While researching smaller and faster alternatives to Magika, I came
across Betlang, a recently introduced language detection library
developed by DioxusLabs for dioxus-code. The fact that it comes from
DioxusLabs gave me more confidence in evaluating this relatively new
dependency for Zed. Betlang embeds an approximately 50 KB model, is
MIT-licensed, and depends only on `fearless_simd`, making it well suited
to Zed's cross-platform embedding requirements.

Detection runs on the background executor with bounded input sampling.
It is restricted to untitled buffers, skips content shorter than 20
bytes, and requires at least 50% confidence. These limits have worked
well in local testing. In release builds on Linux with an Intel Core
i5-13600KF, the `betlang::detect` call alone typically completes within
3 ms when processing the maximum sampled input.

## Testing

I added a test for language detection in untitled buffers that covers
both manually entered and pasted content. The test passes successfully.
I also manually tested the feature to verify that the overall experience
works well.

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



https://github.com/user-attachments/assets/96e28ad7-2968-4325-9aff-37fe813a2da7



---

Release Notes:

- Added automatic language detection for untitled buffers.

---------

Co-authored-by: Max Stevens <maxstevens2708@gmail.com>
2026-07-20 05:12:49 +00:00
Austin Cummings 4a1ed927ff Fix preview button acting on the focused editor instead of its own pane (#61218)
Closes #54951

## Problem

The quick action bar's preview button (markdown, SVG, and CSV behind the
feature flag) resolved everything through `workspace.active_item()` —
the globally *focused* item — instead of the item of the pane the button
sits in. With `A.md` in the left pane and focus in `B.md` in the right
pane:

- Clicking the eye button in **A.md's** toolbar opened a preview of
**B.md**, in the right pane.
- Focusing a non-previewable file (e.g. `B.sh`) in one pane hid the
button in **every** pane's toolbar, making `A.md` unpreviewable by
mouse.

Clicking the button dispatched the `OpenPreview` action, whose
workspace-level handler re-resolved the focused editor — so a click on a
specific pane's toolbar was functionally identical to pressing the
keybinding, discarding the pane the click happened in.

## Fix

Make the flow pane-explicit end to end:

- **Visibility:** each pane's `QuickActionBar` resolves the preview type
from its own `active_item` (set via `set_active_pane_item`) instead of
the workspace's focused item.
- **Click:** no more action dispatch. The handler resolves its pane via
`Workspace::pane_for` and calls new pane-explicit helpers —
`open_preview_in_pane` / `open_preview_to_the_side_of_pane` — extracted
from the action-handler bodies in all three preview crates. Keyboard
actions keep their focus-based semantics and route through the same
helpers with the focused editor and active pane.
- **Alt-click** (open in split) now splits relative to the button's pane
via the new `Workspace::adjacent_pane_of` (the existing `adjacent_pane`
delegates to it).

Notably *not* done: focusing the button's pane and re-dispatching the
action. `workspace.active_pane` only updates when pane focus-in
listeners fire at the end of the next draw, while dispatched actions run
before it — the handler would still read the stale pane.

## Additional changes

- Existing-preview lookup now happens **before** view construction,
instead of building a full preview view (subscriptions, initial parse)
and discarding it when one already exists.
- The `focus` flag now also applies to the activate-existing branch, so
open-to-the-side never steals focus — previously the *first* invocation
left focus in the editor but a *repeat* invocation focused the existing
preview (and cancelled collaborator-following in that pane as a side
effect).
- SVG handlers no longer double-check `is_svg_file`; CSV handlers reuse
`resolve_active_item_as_csv_editor` instead of inlining it;
`is_markdown_file` takes `&App` instead of a needless `&mut Context<V>`.

## Testing

- New regression test
`preview_opens_for_the_given_pane_not_the_focused_editor` reproducing
the issue's setup (two panes, focus in the second, preview invoked for
the first pane's editor), asserting the preview opens in the invoking
pane bound to that pane's editor with the focused pane untouched.
- Markdown/SVG/CSV preview suites and the full `workspace` suite pass;
`./script/clippy` is clean.

Release Notes:

- Fixed the preview button (Markdown/SVG) previewing the focused file
instead of the file in the pane the button belongs to when multiple
panes are open
2026-07-20 04:08:28 +00:00
Sathwik Chirivelli fdedc0c2b7 branch_picker: Add remote icons and fix edge cases (#61215)
# Objective

Make the branch picker easier to scan and ensure branch creation and
remote icons behave consistently across All, Local, and Remote filters.

## Solution

- Group local and remote branches under their own headers in the All
filter.
- Place the create-branch option above branch sections when there is no
exact branch-name match.
- Resolve each remote's hosting provider from its URL and show the
provider icon for branches from that remote.
- Include remote URLs in remote-workspace repository responses so
arbitrary remote names work without hardcoding `origin` or `upstream`.

## Edge Cases Fixed

- An exact branch can exist outside the active Local or Remote filter.
The picker now checks all branches before offering to create a duplicate
branch.
- A non-exact search can return fuzzy branch matches and a create
action. The create action now stays at the top, before the Local and
Remote section headers.
- When a filtered search has no branch matches, the create action is
shown without incorrectly placing it under a Local Branches or Remote
Branches header.
- Repositories can use any remote name, not only `origin` and
`upstream`. Provider icons are resolved independently for every
configured remote.
- Remotes hosted on an unknown or unsupported forge use the generic
server icon instead of implying a desktop or a specific provider.
- Remote-workspace repositories carry the same remote-name-to-URL data
as local repositories, so their branch icons follow the same
provider-resolution path.

## Testing

- `cargo check -p git_ui --no-default-features`
- Branch picker test suite (17 tests)
- `git diff --check`

Tested on macOS.

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

<img width="560" height="522" alt="Screenshot 2026-07-17 at 11 19 27 PM"
src="https://github.com/user-attachments/assets/28d57315-b859-4a8d-86ca-53f9fb513bf5"
/>

The updated branch picker groups local and remote branches, keeps the
create-branch action above those sections, and shows forge-specific
icons for remote branches.

---

Release Notes:

- Improved branch picker filtering, grouping, branch creation
suggestions, and remote-provider icons.
2026-07-20 04:00:48 +00:00
Finn Eitreim ced39bbd9f markdown: Fix inline HTML block highlighting (#61212)
# Objective

Fixes #59304

Right now inline html tags don't render with any kind of highlighting,
despite the fact that non-inline html tags do get highlighting.

## Solution

Right now zed already has tree-sitter rules that identifies the inline
blocks so we can add a new tree-sitter grammar rule,
```
((html_tag) @injection.content
  (#set! injection.language "html")
  (#set! injection.combined))
```
that passes these blocks to the html language server.

## Testing

I did some manual testing:


https://github.com/user-attachments/assets/92e5b322-bbc1-48c3-a615-0d32acc2e7d6

And also added a test:
test_markdown_inline_html_highlighting


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

- markdown: Fixed inline html block highlighting.
2026-07-20 03:52:32 +00:00
ᴀᴍᴛᴏᴀᴇʀ 8f631833cf workspace: Fix bottom dock clipping when resizing windows (#61161)
# Objective

Fixes #59983.

Reducing the Zed window height with the terminal open can clip the
Bottom Dock and terminal content. The dock should shrink to remain
within the workspace instead of extending beyond the window.

## Solution

Restore height clamping for Bottom Dock panels by skipping
`clamp_panel_size` only when a panel actually uses flexible width.
Flexible sizing remains unchanged for the Left and Right Docks, while
Bottom Dock panels once again reduce their stored height to fit the
available workspace.

## Testing

Added a regression test that distinguishes flexible Bottom and Right
Dock behavior. It confirms that the Bottom Dock is clamped while the
flexible-width Right Dock is not. The test failed with the previous
condition and passed with this change.

Manually verified the reported window-resizing scenario locally.


## Self-Review Checklist:

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

## Showcase

+ Before


https://github.com/user-attachments/assets/c56995a8-47c6-45b6-aeb4-b0b56477c737

+ After


https://github.com/user-attachments/assets/97b5ca6f-cf6f-4dd5-b981-e44bd8139490

---

Release Notes:

- Fixed bottom dock clipping when resizing windows.
2026-07-20 03:31:10 +00:00
Remco Smits 7658ca26a9 recent_projects: Fix stale information when removing project from a group (#61062)
# Objective

Before this PR we would show inside the recent project picker the
projects per group (window) which is great, but when you were trying to
remove a project from the group it would show you a label that includes
the just removed project and also when you clicked on it, it would bring
you back to the 2 project's in the same window in this case.

## Solution

My solution is when we actually remove the project from a group, we also
update the group key that includes the newly updated path list, that
should no longer have the removed project path in it. I also refactored
it a bit so we have one method that does the project removing part so we
don't have to duplicate this logic.

## Testing

You can produce this when you do the following:
1. Open Zed
2. Add 2 projects to your window using the project panel
3. Open the recent project picker
4. See that the `This window` header shows 2 projects
5. Remove one of the projects
6. See that below the `This window` header we would show you a entry
that shows you `projectA, projectB` where **projectb** should be removed
from the group.

I also added a regression test that covers this issue, so we can make
sure the change actually works and does not regress of couse :).

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

**Before** (**Note** before this change we showed the group project
names comma seperated)


https://github.com/user-attachments/assets/750358f4-f347-4f91-86b7-6500b2e09af9

**After** (**Note** after we now updated the groups key so it does not
include the removed project)


https://github.com/user-attachments/assets/f15acea8-d936-4aab-b5c2-324ee49f74a2

---

Release Notes:

- Recent projects: Fixed that it shows you a removed project from a
group
2026-07-20 03:30:22 +00:00
Xin Zhao 9005ced680 vim: Fix selection motions when trailing newline is selected (#61253)
# Objective

Closes #41743

When selecting text on the last line, excluding the trailing newline,
Vim and Helix modes behave differently from native Vim and Helix when
the file has a trailing newline:
1. We cannot use `l` (move right) to include the final `\n` in the
selection, while native Vim and Helix allow this.
2. By default, the rendered cursor should appear on the selected
character. When that character is the final `\n`, however, Zed renders
the cursor on the synthetic empty line after it rather than at the end
of the preceding line. This differs from native Vim and Helix, as well
as from Zed's behavior for newlines elsewhere in the file.
3. When the final `\n` is selected, it affects subsequent selection
motions, as reported in #41743.

The cause is several special-case guards for trailing newlines in Visual
and Select modes. These guards exist in the cursor rendering logic:

https://github.com/zed-industries/zed/blob/73523ec50bafcdab9308fa51808bef074ae898bc/crates/editor/src/element.rs#L201-L213

They also exist in the Visual motion logic for Vim mode and the Select
motion logic for Helix mode (the Helix implementation was adopted
directly from Vim in #43234):

https://github.com/zed-industries/zed/blob/73523ec50bafcdab9308fa51808bef074ae898bc/crates/vim/src/visual.rs#L254-L259

Finally, they exist in the selection extension logic for Vim and Helix
(the Helix logic was also adopted from Vim):

https://github.com/zed-industries/zed/blob/73523ec50bafcdab9308fa51808bef074ae898bc/crates/vim/src/visual.rs#L273-L284

These guards cause trailing-newline selections to behave inconsistently
with selections containing newlines elsewhere in the file.

## Solution

Remove all the guards mentioned above, including those in cursor
rendering, Visual and Select motions, and selection extension. And due
to the cursor rendering logic is also changed, an exsisting test is
updated.

After removing these guards, I could not reproduce the unexpected
behavior described in the existing comments:

https://github.com/zed-industries/zed/blob/73523ec50bafcdab9308fa51808bef074ae898bc/crates/vim/src/visual.rs#L247-L253

The only remaining difference is that, when the cursor is on the last
line in Visual mode, pressing `j` moves it to the final `\n` rather than
to the synthetic empty line after it. In comparison, native Vim and
Helix do nothing in this case.

## Testing

- Built and tested locally.
- Added new GPUI tests.

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

- Improved Vim Visual and Helix Select modes when selections include a
trailing newline.
2026-07-20 03:19:55 +00:00
ᴀᴍᴛᴏᴀᴇʀ 0ccd4b7613 editor: Fix opaque multibuffer header backgrounds not rendering in transparent themes (#61268)
# Objective

As part of the transparent-window artifact fixes in #58981, multibuffer
header backgrounds stopped rendering whenever the window was transparent
or blurred.

This caused a regression for transparent themes, which commonly use an
opaque multibuffer header background to prevent editor text from showing
through sticky headers.


## Solution

Render `editor_subheader_background` when either the window or the
configured background color is opaque.

This restores opaque multibuffer header backgrounds as a mask for the
editor content beneath them, while preserving the #58981 behavior for
translucent backgrounds that would otherwise create a darker layered
region.

## Testing

Manually verified locally with a transparent theme that an opaque
multibuffer header background is rendered and prevents editor text from
showing through sticky headers.

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

**Nightfox - opaque / blurred**

Before:

<img width="2566" height="1771" alt="图片"
src="https://github.com/user-attachments/assets/55b333bc-b029-4079-9bbc-86462a3f41a7"
/>


After:

<img width="2444" height="1687" alt="图片"
src="https://github.com/user-attachments/assets/217e1ee7-717c-4961-8db0-5eac8104e5bb"
/>

---

Release Notes:

- Fixed editor text showing through multibuffer headers and overlapping
header text in transparent themes.
2026-07-20 03:07:34 +00:00
tidely f839ff93ed editor: Reduce allocations during editor prepaint (#61290)
Found some unnecessary allocations and an `.unwrap()` while working on a
separate issue. The PR makes no behavior changes and should be trivial
to review.

## Testing

All tests pass. These changes are not expected to change any behavior.

None of the changes are interleaving, so it should be easy to review
top-down. Reasoning for each change can be read from individual commit
messages.

Release Notes:

- N/A or Added/Fixed/Improved ...
2026-07-20 02:52:15 +00:00
Xin Zhao 67341c7d9e editor: Fix Git blame gutter width with avatars (#61287)
# Objective

When using column Git blame with avatars enabled, blame entries whose
author name is the longest in the buffer can exceed the blame border.

For example, line 10 of `crates/vim/src/visual.rs` is displayed as
follows:

<img width="998" height="121" alt="issue"
src="https://github.com/user-attachments/assets/eff3e1ff-bd1c-42af-ae9b-da8efb0a7c22"
/>

The blame contents exceeds the width.

The root cause is in the blame width calculation:

https://github.com/zed-industries/zed/blob/4feae499a62c4ab971a47dfbbd0667e944322ee1/crates/editor/src/editor.rs#L11583-L11598
The calculation accounts for the commit SHA, author name, and timestamp.
Other elements, including spacing, margins, and the avatar, are
represented by the fixed `SPACING_WIDTH` constant.

For typical fonts, `ch_advance` is approximately `0.5rem` to `0.6rem`,
so `SPACING_WIDTH` provides approximately `2rem` to `2.4rem` for
non-text content. However, the avatar itself occupies `1rem`:

https://github.com/zed-industries/zed/blob/4feae499a62c4ab971a47dfbbd0667e944322ee1/crates/ui/src/components/avatar.rs#L81
When avatars are displayed, the entry also contains three `0.5rem` gaps
and also one `0.5rem` right margin:

https://github.com/zed-industries/zed/blob/4feae499a62c4ab971a47dfbbd0667e944322ee1/crates/git_ui/src/blame_ui.rs#L170-L188

This requires approximately `3.0rem`, which can exceed the space
provided by `SPACING_WIDTH`. When an entry contains both the longest
author name in the buffer and a long timestamp, its content can
therefore exceed the blame border.

## Solution

The simplest fix would be to increase `SPACING_WIDTH`, but that would
still rely on an approximate conversion between editor character widths
and UI dimensions.

Instead, this PR adds a method to the blame renderer for calculating the
non-text width of a blame entry. The editor uses this value together
with the measured text width when calculating the final blame width.

## Testing

Tested locally. A before-and-after comparison is included below.

## Self-Review Checklist:

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

## Showcase

| Before | After |
| :--: | :--: | 
| <img width="551" height="94" alt="Before"
src="https://github.com/user-attachments/assets/b6741a41-6531-4fae-adaa-f9ae0b298e0f"
/> |<img width="566" height="93" alt="After"
src="https://github.com/user-attachments/assets/e8d75d2a-6b07-43f6-b2a8-bfb76d118611"
/> |

Release Notes:

- Fixed Git blame entries overflowing the gutter when avatars are
displayed.
2026-07-20 02:50:00 +00:00
Finn Eitreim a07c26f03a editor: Fix line selection disappears when the cursor goes off screen (#60054)
# Objective

When you make a line selection in a row that is long enough to multiple
lines long while wrapped the selection box will disappear when the
cursor (or just origin of the line selection goes off screen).


## Solution

The when you are in line selection mode the `SelectionsCollection` just
enables `line_mode`, instead of storing the whole ranges of those line
selections, so the Anchor of the selection is a single point.
`disjoint_in_range` filters all the disjoint selections of the
collection to fit inside some range, this is used to render the
selection boxes on screen. `disjoint_in_range` had no special case for
`line_mode` causing it to filter on the point instead of the bounds of
the selection.

My fix is too add a case for `line_mode` that changes the filtering
`Anchor` -> `Point` and then only filters on the row. Then use the
proper bounds of the selection with that:
```rust
        let (start_ix, end_ix) = if self.line_mode {
            let start_row = range.start.to_point(buffer).row;
            let end_row = range.end.to_point(buffer).row;
            let start_ix = self
                .disjoint
                .partition_point(|probe| probe.end.to_point(buffer).row < start_row);
            let end_ix = self
                .disjoint
                .partition_point(|probe| probe.start.to_point(buffer).row <= end_row);
            (start_ix, end_ix)
        } else {
        ...
```

## Testing

Before:


https://github.com/user-attachments/assets/a443de39-53d7-4ee4-b3af-d3be99ca1fcf

After:


https://github.com/user-attachments/assets/18c1c7ef-45cc-4dc8-9a8b-241252c376ab

I also added some tests `disjoint_in_range_line_mode_matches_whole_row`,
being the one that really tests this behavior. the other two are just
for `disjoint_in_range`

I am using macOS 27.0 Beta (26A5368g), but I noticed this bug before
upgrading.

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

- editor: Fixed bug where selection boxes wouldn't render when the
cursor was offscreen.
2026-07-20 02:07:59 +00:00
Xin Zhao 1625b90fd1 Preserve Markdown emphasis delimiters when joining lines (#61298)
# Objective

When joining lines, Zed checks the next line and strips comment,
documentation-comment, and unordered-list delimiters. The logic trims
whitespace from these delimiters, then checks whether the next line
starts with the trimmed delimiter. If it does, Zed removes the delimiter
before joining the lines.

This works for comment and documentation-comment delimiters, where
trailing whitespace does not affect their meaning. However, it causes
unexpected behavior for unordered-list delimiters, which, as far as I
know, are unique to Markdown.

In Markdown, `* ` is an unordered-list marker, while `*` is also used as
an emphasis delimiter, such as `*italics*` and `**bold**`. The current
logic strips the leading `*` from these emphasis cases, which it should
not.

## Solution

For unordered-list delimiters, Zed should strip the exact delimiter,
such as `* `, rather than the trimmed `*`. It should strip a bare `*`
only when the next line contains only `*`.

## Testing

Tested locally and new GPUI tests were added.

## 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 markdown emphasis delimiters being removed when joining lines.
2026-07-20 02:03:51 +00:00
Lukas Wirthandzed-zippy[bot] dc761ccb47 zed: Log worktree info when memory jumps unexpectedly (#61283)
Release Notes:

- N/A or Added/Fixed/Improved ...

---------

Co-authored-by: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>
2026-07-19 12:46:31 +00:00
John Tur 4feae499a6 Reduce overdraw for border-only quads (#61274)
Restore an optimization that I mistakenly removed in
https://github.com/zed-industries/zed/pull/54728.

Drawing a quad with a border but no fill color will run the quad
fragment shader for every transparent interior pixel, which is
especially costly when the quad is large. Instead, split these quads
into four non-overlapping strips that cover the regions where borders
are painted. The side strips own the straight left and right edges,
while the top and bottom strips own the horizontal edges and the rounded
corners.

Previously, this optimization only applied to borders drawn by the Taffy
layout. I've decided to reinstate the logic directly in `paint_quad` so
that the optimization can be applied more generally... though if this
feels like too much policy, we can move it back.

This reduces the GPU time spent painting a representative Zed scene by
about 20% or so.

Release Notes:

- N/A
2026-07-19 06:52:53 +00:00
Miguel Raz Guzmán Macedo 78652e2f50 Fix several small performance inefficiencies in hot paths (#61275)
# Objective

Land five small, independent performance fixes found during an audit of
hot paths (anchor resolution, line shaping, worktree scanning, and
sorting in multibuffers).

## Solution

Each fix is its own commit, so **this PR is best reviewed
commit-by-commit** — every commit message contains the full reasoning
for that change:

- `text`: Avoid redundant rope traversal in `Anchor → usize` conversion
— call `offset_for_anchor` directly instead of `summary_for_anchor`,
which recomputed the same byte offset with ~4 extra O(log n) tree walks.
This is the hottest anchor-resolution path.
- `editor`: Avoid double allocation per shaped line —
`line.as_str().into()` instead of `line.clone().into()`, which allocated
twice per visible line, every frame.
- `text`: Use `sort_unstable_by_key` in operation queue insertion —
Lamport timestamps are unique keys and duplicates are deduped right
after, so stability buys nothing.
- `multi_buffer`: Sort with an explicit comparator instead of
`sort_unstable_by_key`, which cloned a `PathKey` (`Arc` refcount bump)
on every comparison.
- `worktree`: Replace O(n²) `Vec::remove` in the deferred-directory pass
with an O(1) `None` assignment — the vec is already
`Vec<Option<ScanJob>>` and is consumed with `.flatten()`.

## Testing

- No behavior changes intended; all changes are mechanical and tests
affected crates pass: `text`, `editor`, `multi_buffer`, `worktree`.

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

- Improved editor performance through several micro-optimizations in
anchor resolution, line shaping, and worktree scanning.
2026-07-19 05:36:35 +00:00
Yifeng Xu c5830a9378 agent_ui: Show controls after every agent message (#61245)
# Objective

Fixes #61244 

In the Agent Panel, after a multi-turn conversation, the action buttons
("Copy this Agent response", "Scroll to User Message", and "Scroll to
top") were only shown after the last assistant response. This was
inconvenient for users who wanted to copy or navigate from earlier
responses.

Additionally, the "Scroll to User Message" button always jumped to the
most recent user message in the entire thread, even when clicked from a
historical assistant response.

This PR addresses both issues by rendering the controls after every
non-blank assistant response, and by making "Scroll to User Message"
jump to the user prompt associated with that specific response.

## Solution

- Refactored `render_thread_controls` in
`crates/agent_ui/src/conversation_view/thread_view.rs` to accept an
explicit `entry_ix`, `copy_response_index`, `is_thread_bottom`, and
`user_message_index`, making it reusable per assistant message.
- Rendered the control bar after each non-blank `AssistantMessage`
entry, not just the last entry.
- Made button IDs unique by using tuple IDs like `("name", entry_ix)`,
matching the existing style in this file and avoiding `format!`
allocations.
- Keyed the copy button ID by the control bar location (`entry_ix`)
while still copying `response_index`'s content, so the bottom fallback
bar doesn't duplicate IDs with the per-response bar.
- Gated the generation/confirmation early return to `is_thread_bottom`,
so historical controls remain accessible while the thread is generating
or waiting for confirmation.
- Gated turn stats and thread feedback buttons to the bottom of the
thread so they only appear on the last response.
- Replaced `scroll_to_most_recent_user_prompt` with a more general
`scroll_to_user_message_index` that takes an optional target user
message index.
- For each per-response button, computed the associated user message
index as the most recent user message before that assistant response.
- For the bottom fallback (when the last entry is not an assistant
message), passed `None` so the button still scrolls to the most recent
user message.
- Updated the tooltip from "Scroll to Most Recent User Message" to
"Scroll to User Message".
- Updated existing tests and added assertions for
`scroll_to_user_message_index(Some(ix), cx)`.

## Testing

- `cargo check -p agent_ui`
- `./script/clippy -p agent_ui`
- `cargo test -p agent_ui --lib` (399 passed)
- Added assertions in `test_scroll_to_most_recent_user_prompt` to verify
`scroll_to_user_message_index(Some(0), cx)` and
`scroll_to_user_message_index(Some(2), cx)` scroll to the correct user
message indices.
- Manual testing recommended: open the Agent Panel, send multiple
messages, and verify that each assistant response has the three buttons
and that "Scroll to User Message" jumps to the corresponding user
prompt.

## Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments (no unsafe blocks)
- [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

Before: Only the last assistant response in the Agent Panel showed the
"Copy this Agent response", "Scroll to User Message", and "Scroll to
top" buttons. Clicking "Scroll to User Message" always jumped to the
most recent user message.

After: Every non-blank assistant response displays these buttons.
Clicking "Scroll to User Message" on a historical response scrolls to
the user prompt that triggered that specific response.


https://github.com/user-attachments/assets/46e02bcc-8bed-4cf3-a08a-9ef91a206d08

---

Release Notes:

- Added "Copy this Agent response", "Scroll to User Message", and
"Scroll to top" buttons to every agent response in the Agent Panel.
- Fixed "Scroll to User Message" so it jumps to the user prompt
associated with the current response, rather than the most recent user
message.
2026-07-18 22:40:55 +00:00
Xiaobo LiuandCole Miller 0c2cf8b508 project: Add remote support for adding paths to .gitignore (#56368)
Release Notes:

- Fixed remote support for adding paths to .gitignore



The problem solved by this PR is: when opening a remote project,
right-clicking a new file in the git panel and clicking "Add to
.gitignore" does not work.

---------

Co-authored-by: Cole Miller <cole@zed.dev>
2026-07-18 21:39:15 +00:00
6f5463ca3c git_ui: Disable commit actions during commit message generation (#51727)
Release Notes:

- Add disable commit actions during commit message generation

---------

Signed-off-by: Xiaobo Liu <cppcoffee@gmail.com>
Co-authored-by: Cole Miller <cole@zed.dev>
Co-authored-by: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>
2026-07-18 20:06:31 +00:00
victorandCole Miller 37d372036d git: Add possibility to open specific line in a diff using the CLI (#45499)
this pr enables opening a specific line in a diff using zed's cli

Release Notes:
- refactor: add possibility to open specific line in a diff using the
cli

---------

Co-authored-by: Cole Miller <cole@zed.dev>
2026-07-18 19:56:01 +00:00
Sathwik Chirivelli 2328aebf25 git_panel: Show staged and unstaged diff stats (#60815)
# Objective

- Show accurate diff stats for each staged and unstaged projection of a
partially staged file in the Git panel.
- This was originally considered for
https://github.com/zed-industries/zed/pull/59884, but was scoped out of
that already-large PR and is being submitted separately as discussed
there.

## Solution

- Collect HEAD-to-index and index-to-worktree diff stats alongside the
existing combined HEAD-to-worktree stats.
- Carry the staged and unstaged stats through repository status
snapshots and remote status serialization.
- Use the stat matching the projected Git panel section while preserving
the combined stat for the other grouping modes.
- Update the fake Git repository and add regression coverage with
deliberately different staged and unstaged counts.

## Testing

- `cargo check -p git_ui`
- `cargo check -p collab`
- `cargo test -p git_ui
test_group_by_staging_section_membership_and_order --lib`
- `cargo test -p project --lib --no-run`
- `cargo fmt --all -- --check`
- `git diff --check`

## 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 diff stats for partially staged files in the Git panel
2026-07-18 19:02:25 +00:00
Jake AbendrothandCole Miller 728cb247e9 buffer_diff: Canonicalize ambiguous hunk placement to fix staging corruption (#60584)
Closes #60424

## Problem

With the repro from #60424, staging the first deletion hunk marked the
second deletion as staged in the UI even though git still had it
unstaged, and clicking the (incorrectly shown) Unstage button inserted a
duplicate copy of the hunk's contents into the git index on every click.

The root cause is ambiguous hunk placement. The committed text contains
repeated `end\n\n` line runs, so the deletion hunks can "slide": more
than one placement produces a minimal diff. The uncommitted diff (HEAD
vs worktree) anchored the remaining deletion at one row while the
unstaged diff (index vs worktree), recomputed after the partial stage,
anchored the same logical deletion at a different row. Everything that
correlates hunks across those two diffs assumes they agree on positions:

- the secondary-status matching in `hunks_intersecting_range_impl` found
no unstaged hunk at the uncommitted hunk's rows and reported it as
staged (`NoSecondaryHunk`);
- the worktree→index projection in `compute_uncommitted_index_edits`
treated the hunk's position as unchanged text and, on unstage, inserted
the hunk's HEAD content at an index position that already contained it,
duplicating it on every request.

## Fix

Upgrade `imara-diff` from 0.1.8 to 0.2.0 and run
`Diff::postprocess_lines` (imara-diff's port of git's xdiff
slider/indent heuristic) after computing hunks in `buffer_diff`. This
canonicalizes the placement of ambiguous hunks based only on their local
content, so diffs of the same buffer against different base texts anchor
the same logical change at the same rows. A bonus is that Zed's hunk
placement now matches `git diff`'s output for such cases (git has used
the indent heuristic by default since 2.11).

As defense in depth, `compute_uncommitted_index_edits` now drops a
pure-insertion index edit whose content is already present at the target
position, so a stale secondary status can no longer duplicate index
content.

The imara-diff 0.2 API removed the `Sink` trait and the top-level
`diff()` function, so the other call sites (`language/text_diff.rs`,
`zeta_prompt/udiff.rs`, `edit_prediction_metrics/reversal.rs`) are
migrated mechanically to `Diff::compute` + `hunks()` with unchanged
behavior (0.2 also renamed `lines_with_terminator` to `lines` and
changed the default `&str` tokenization to include terminators; the
unified-diff builders keep terminator-less tokens via `str::lines()`).

## Testing

- New regression test `test_staging_hunks_with_ambiguous_placement`
replays the exact repro from #60424 (same file contents): stages the
first deletion, asserts the remaining hunks keep their unstaged status
and the index matches exactly, then issues repeated unstage requests for
the unstaged hunk and asserts the index is unchanged. Before the fix
this test showed the second hunk flipping to staged and the index
growing by one copy of the deleted block per unstage request.
- `buffer_diff`, `language`, `zeta_prompt`, `edit_prediction_metrics`,
`multi_buffer`, `git_ui`, `editor`, and the `project` integration suite
pass.
- One test expectation updated: `editor::test_fold_function_bodies`
asserted the old placement of an ambiguous deletion (blank line before
comment); the canonicalized placement (comment before blank line)
matches what `git diff` produces for the same texts.

Release Notes:

- Fixed staging a hunk sometimes marking a different hunk as staged (and
subsequent unstaging corrupting the git index) when the diff contained
repeated lines
([#60424](https://github.com/zed-industries/zed/issues/60424)).

---------

Co-authored-by: Cole Miller <cole@zed.dev>
2026-07-18 18:48:49 +00:00
saberoueslati 641daf4f8c editor: Fix Shift-click selection after cursor movement (#61045)
## Context

Shift-click sometimes extended a selection from an earlier word boundary
after double-clicking a word and moving the cursor with the arrow keys.
Cursor movement changed the selection but left the word or line
selection mode active, so the next Shift-click reused stale selection
bounds. Selection movement now resets the mode to character mode
whenever it changes the selection, while preserving valid empty line
selections that have not been moved.

Closes #59913.

Behavior before the fix :

[Screencast from 2026-07-15
13-21-51.webm](https://github.com/user-attachments/assets/c126adfe-f9db-4a04-91c2-6db6e8070182)

Behavior after the fix :

[Screencast from 2026-07-15
13-19-38.webm](https://github.com/user-attachments/assets/19c9f5b6-aaf8-4e8b-b4c5-70327411d1b9)


## How to Review

**`crates/editor/src/selections_collection.rs`**:
`MutableSelectionsCollection::move_with` now resets the selection mode
to character mode when movement changes a selection.

**`crates/editor/src/editor_tests.rs`**: Regression tests cover
Shift-click after collapsing a word selection and confirm that a valid
empty line selection retains line-wise extension behavior.

## Self-Review Checklist

- [x] I've reviewed my own diff for quality, security, and reliability
- [ ] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the UI/UX checklist
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

Release Notes:

- Fixed Shift-click sometimes extending selections from a previous word
or line boundary.
2026-07-18 15:51:21 +00:00
Lukas Wirth 28b8e5812d workspace: Run possible_open_target logic on the background (#61257)
This is a lot of computation work which otherwise hangs the ui thread

Closes FR-122

Release Notes:

- Fixed a cause for ui hangs when interacting with the agent panel
2026-07-18 14:45:31 +00:00
Kevin Bravo 73523ec50b lsp: Set workspace folder names (#60938)
# Objective

Fixes #60518.

Zed sends an empty `name` for entries in
`initialize.params.workspaceFolders`. Language servers such as
basedpyright use this field to identify workspace service instances,
resulting in an unnamed instance.

## Solution

Derive each workspace folder name from its URI, preferring the decoded
filesystem basename. For basename-less URIs, fall back to a non-empty
path, URI path segment, or the full URI.

Use the same construction for initialization parameters, dynamic
workspace-folder notifications, and `workspace/workspaceFolders`
responses so all LSP messages remain consistent.

## Testing

- `cargo fmt --all -- --check`
- `cargo test -p lsp`
- `cargo check -p project --all-targets --all-features`
- `./script/clippy -p lsp`
- `./script/clippy -p project`

Reproduced with basedpyright 1.39.9 over an LSP stdio session. Before
this change it logged:

```text
Starting service instance ""
```

With a derived workspace folder name it logged:

```text
Starting service instance "zed-60518-project"
```

Tested on macOS.

## 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 language servers receiving empty workspace folder names.
2026-07-18 08:04:17 +00:00
Eric HolkandDanilo Leal ce3a79d607 Round window corners on the sidebar side on Linux (#61229)
On Linux with client-side decorations, opening the workspace sidebar
squared off the window corners on the sidebar's side while the rest of
the window stayed rounded:

Before:
<img width="366" height="239" alt="image"
src="https://github.com/user-attachments/assets/e0ee8d28-6143-42ea-bfd2-10d069df5492"
/>

After:
<img width="426" height="219" alt="image"
src="https://github.com/user-attachments/assets/51d2979d-0103-4742-90bd-a97f5837d99b"
/>

Previously, `client_side_decorations` took a `border_radius_tiling`
override that `MultiWorkspace` used to deliberately square the window
shape on the sidebar's side, since the sidebar painted a square
background that would otherwise poke out past the rounded window border.
The title bar and status bar already skip rounding their corners on the
sidebar side, implying the sidebar is expected to own those window
corners — it just never rounded them.

This PR makes the sidebar round its outer corners the same way the title
bar and status bar do (including overlapping the 1px window border on
untiled edges to avoid a transparent gap in the rounded corners), and
removes the now-unneeded `border_radius_tiling` parameter so the window
border and backdrop round purely based on actual tiling state.

Only applies when the window uses client-side decorations, so macOS and
Windows are unaffected.

Fixes #54724 

Release Notes:

- Fixed square window corners on the sidebar side of client-decorated
(Linux) windows when the workspace sidebar is open.

---------

Co-authored-by: Danilo Leal <67129314+danilo-leal@users.noreply.github.com>
2026-07-17 23:58:06 +00:00
John Tur 2e405c7c7a gpui: Remove ExitProcess shutdown workaround (#61219)
The issue with aws-lc that necessitated this workaround has been fixed
upstream: https://github.com/aws/aws-lc/issues/3197.

Release Notes:

- N/A
2026-07-17 19:16:49 +00:00
Lukas WirthandJohn Tur cd91c84675 gpui: Add system notification platform APIs (#61189)
Release Notes:

- N/A or Added/Fixed/Improved ...

---------

Co-authored-by: John Tur <john-tur@outlook.com>
2026-07-17 18:52:23 +00:00
Jason WilliamsandAnthony Eid 31813161f1 debugger: Don't eagerly fetch variables for expensive DAP scopes (#61144)
# Objective

Zed eagerly fetches variables for every scope returned by a DAP `scopes`
response, including scopes the adapter marked `expensive: true`.

Per the [DAP
spec](https://microsoft.github.io/debug-adapter-protocol/specification#Types_Scope),
`expensive` means "the number of variables in this scope is large or
expensive to retrieve... recommended for UIs to not automatically expand
and evaluate the scope. Some debug adapters (e.g. `vscode-js-debug`,
used for JavaScript/Chrome debugging) mark scopes like "Global" as
expensive because resolving them can hang forever. VS Code honors this
and leaves the scope collapsed until the user opts in by expanding it;
Zed did not, so any session with a hanging expensive scope would freeze
the entire debug session (including Resume) with no user action at all.

Fixes #61105

## Solution

- `Session::scopes()` in `crates/project/src/debugger/session.rs`
[unconditionally called
`this.variables(...)`](https://github.com/zed-industries/zed/blob/b8a184ba26acdddf24e305e2ffad7f9c0d0dd920/crates/project/src/debugger/session.rs#L2538)
for every scope in the `scopes` response.
- `VariableList::build_entries()` in
`crates/debugger_ui/src/session/running/variable_list.rs` also called
`session.variables(...)` [on every
scope](https://github.com/zed-industries/zed/blob/b8a184ba26acdddf24e305e2ffad7f9c0d0dd920/crates/debugger_ui/src/session/running/variable_list.rs#L291-L304),
as a side effect of checking whether it was empty (used to decide
whether to hide it from the tree). Fixing only the first call site
wasn't enough, since this one would still trigger the fetch on the very
next render.
  
Both now skip the fetch for `expensive` scopes. Expensive scopes still
show up in the variable list, collapsed, so the user can expand them
manually (which fetches lazily via the existing on-toggle path). Also
hardened the auto-expand heuristic (e.g. "expand the only scope if it's
not Locals") to never auto-expand an expensive scope, even in adapters
where it happens to be the sole or "Locals"-named scope.

## Testing

- Added `test_expensive_scope_is_not_eagerly_fetched` in
`crates/debugger_ui/src/tests/variable_list.rs`, asserting the DAP
`variables` request is never sent for an
`expensive: true` scope until the user expands it, and that expanding it
does trigger the fetch. Verified this test fails on the old code and
passes with the fix.
  - Ran the full `debugger_ui` test suite, all pass, no regressions.
- Manually reproduced and verified the fix using the minimal repro at
https://github.com/jasonwilliams/zed-dap-repro

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

Before:

https://github.com/user-attachments/assets/7a3ead7e-aece-4726-883d-d60d49c83b7c
Here you can see that once the break has happened Zed has crashed,
resuming doesn't help, i effectively need to kill the whole debug
session.

After:

https://github.com/user-attachments/assets/7a36cbb0-f22b-4782-9326-9ccab9297fc7
Here you can see the Global scope is closed and clicking resume carries
on without any crashes

Release Notes:

- Fixed debugger eagerly fetching expensive variable scopes

---------

Co-authored-by: Anthony Eid <anthony@zed.dev>
2026-07-17 14:42:46 +00:00
tidely 9948409b40 gpui: Unify raw-window-handle dependency (#61193)
Just something I noticed while skimming through dependencies

Release Notes:

- N/A or Added/Fixed/Improved ...
2026-07-17 13:41:05 +00:00
Smit Barmase 5f624dbe96 git: Fix operations timing out and commit-msg hook being skipped (#61185)
Closes #44926
Closes #43157
Closes #29903

We have an askpass 17s timeout that races against Git operations and
results in "Connecting to host timed out". It came along in #25953 when
we extracted askpass out of remoting, where it was used for SSH.

I think, for SSH connection, no prompt and no connection after 17
seconds means the host is unreachable, so the timeout is a reliable
signal there. But for Git, silence is pretty normal. Cases like hook
running, pack transferring, an ssh-agent waiting on a fingerprint are
all senarios where we should not be dependent on timeout which kills
these healthy operations.

#43285 worked around this for commits by running the pre-commit hook
manually and passing `--no-verify` to `git commit`. But, there are more
problems to address, which I reproduced on my machine:

1. A slow `post-commit` hook fails, since `--no-verify` doesn't skip it.
2. A slow `pre-push` hook fails too, and a workaround like #43285 needs
a lot more handling. See
https://github.com/zed-industries/zed/pull/42946#issuecomment-3550570438.
3. This is the tough one: due to `--no-verify`, we are also skipping the
`commit-msg` hook. There is no direct way to call that hook since, Git
hands this hook its in-progress message file, commits whatever the hook
leaves in it, and aborts if the hook exits non-zero. Reproducing that
outside `git commit` means reimplementing that.
4. An ssh-agent waiting for user approval fails after the timeout, like
if you have 1Password set up.
5. It doesn't solve large fetches. Fetching
`git@github.com:torvalds/linux.git` just dies at the 17s timeout
mid-download.

This PR fix keep the timeout only on the SSH transport and drop it for
Git, which is less of a behavior change and more of a restoring its
original scope. If Git in a terminal doesn't time out, we shouldn't
either. This way, we let Git handle all types of hooks, which solves the
hooks issue along with the timeout issue. _This follows how VS Code does
it. It does not have any kind of timeout on git child process, and hooks
are handled by Git itself._

Edit: I also think working towards way to cancel long going operations
is better way forward. See
https://github.com/microsoft/vscode/issues/171353.

Hooks still don't run for untrusted repositories, the existing
`core.hooksPath=/dev/null` clamp covers that. The `RunGitHook` proto
handler is kept for compatibility with older remote clients.




Release Notes:

- Fixed git operations failing with a misleading "Connecting to host
timed out" error when they took longer than 17 seconds (large fetches,
slow hooks, or waiting on agent-based authentication like 1Password
Touch ID).
- Fixed `commit-msg` hooks being silently skipped on commit.
2026-07-17 13:38:09 +00:00
ᴀᴍᴛᴏᴀᴇʀandTom Houlé 6c4862e1f2 gpui_linux: Fix unbounded memory growth when composing text with Fcitx5 under KWin/Wayland (#61079)
# Objective

Close #61034.

Fix unbounded memory growth when composing text with Fcitx5 under
KWin/Wayland.

While a non-empty preedit is cached, KWin resends it whenever it
receives a text-input-v3 `commit()` ([relevant KWin
code](https://github.com/KDE/kwin/blob/0e473e87a64d5d404c2fecf5516a9a5c3cf17d91/src/wayland/textinput_v3.cpp#L444-L504)).

Zed handles the replayed preedit as a buffer edit. This invalidates the
IME character coordinates, causing Zed to submit the same cursor
rectangle and call `commit()` on the next frame. That commit makes KWin
replay the cached preedit again, forming an infinite feedback loop.

The observed memory growth is caused by retained CRDT state accumulating
indefinitely.

## Solution

Following [SDL's solution to the same
problem](https://github.com/libsdl-org/SDL/commit/81479d8784d0e1a61eafb3a444dd3865ad762fb2),
cache the last submitted cursor rectangle and compare it with the new
rectangle before calling `set_cursor_rectangle()`.

If the rectangles are equal, skip both the rectangle update and its
associated `commit()`. The initial cursor rectangle and actual rectangle
changes during an active composition are still submitted, preserving the
candidate-window positioning behavior introduced by #59911.

## Testing

Manually tested on KDE Plasma with `fcitx5-chinese-addons`. 

Before the fix, memory usage grew continuously while preedit text was
present, with `WAYLAND_DEBUG=client` showing text-input events repeating
indefinitely.

After the fix, the repeated events stopped and memory usage remained
stable.

No automated test was added because reproducing the feedback loop
requires compositor-specific KWin text-input-v3 behavior.

## Self-Review Checklist:

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


---

Release Notes:

- Fixed excessive memory usage when composing text with Fcitx5 on KDE
Wayland.

---------

Co-authored-by: Tom Houlé <tom@tomhoule.com>
2026-07-17 13:10:42 +00:00
d0 ec06066302 outline: Add preview pane to buffer symbols (#61069)
# Objective

- Implement preview pane for buffer symbols, similar to #59863 

## Showcase
### Before 
<img width="4512" height="2980" alt="CleanShot 2026-07-15 at 23 25
19@2x"
src="https://github.com/user-attachments/assets/443f150a-bb67-4bac-ba4a-f8f299554470"
/>

### After
<img width="4512" height="2980" alt="CleanShot 2026-07-15 at 23 19
09@2x"
src="https://github.com/user-attachments/assets/0fd4be89-d25e-4052-8de0-3a9a5a5908f9"
/>


---

Release Notes:

- Added a preview pane to the buffer symbols picker
2026-07-17 11:41:08 +00:00
Ibrahim Khan fc11498fb4 agent_ui: Fix project rule pluralization in context usage popover (#61184)
The agent panel's context usage popover showed "1 project rules" when
exactly one project rule (e.g. `.rules`) was loaded, because the
project-rules button used an unconditional `format!("{} project rules",
...)`.

Reuse the existing `pluralize` helper (already used for diagnostics
labels in the same crate) so a single rule renders as "1 project rule"
and multiple rules render as "N project rules". The sibling "1 global
rule" label is intentionally left unchanged, since there is only ever
one global rule.

Closes #57759

Release Notes:

- Fixed the agent panel context usage popover showing "1 project rules"
instead of "1 project rule" when a single project rule is loaded.
2026-07-17 11:36:37 +00:00
Danilo Leal 848212b74e git_graph: Remove commit preview on row hover (#61191)
This PR removes the commit preview popover when hovering over rows in
the git graph. In my humble opinion, I've been finding that having the
hover preview damages the usability/readability of the graph. I can't
properly read each row's content and understand its place on the graph
if everywhere I rest my cursor in a popover appears... Moreover, almost
all of the information we display in the commit preview is already
displayed in the row itsself, and if you'd like to drill down into the
commit description and whatnot, clicking the row opens the commit drawer
and gives you that and even more information (e.g., set of changed
files, etc.).

Release Notes:

- N/A
2026-07-17 11:32:07 +00:00
Kirill Bulatov 28ed883b99 Bump taffy (#61183)
Follow-up to https://github.com/zed-industries/zed/pull/60721

Release Notes:

- N/A
2026-07-17 09:45:16 +00:00
Kirill Bulatov 84430455ad Mimic macOS bundling behavior for Windows builds (#61180)
Rei-mplements the logic from
https://github.com/zed-industries/zed/blob/cf028dbd3ef1edf1d09027458d208821be7e8976/script/bundle-mac#L120-L123
for Windows bundling so that `run-bundling` label in CI can build
unsigned Windows binaries properly.

Release Notes:

- N/A
2026-07-17 09:01:06 +00:00
Lukas Wirth df0ab34aed git_graph: Fix commit message overflowing into changed files section (#61177)
This regressed in https://github.com/zed-industries/zed/pull/59674

Closes FR-125

Release Notes:

- Fixed an issue where the commit message in the git panel could overlap
other content
2026-07-17 08:57:46 +00:00
Lukas Wirth 330ec055b3 project: Fix agent hanging indefinitely when pulling workspace diagnostics (#61176)
The agent's diagnostics tool waits on pull_workspace_diagnostics_once,
which enqueues a completion signal into the background workspace
diagnostics refresh loop. When a language server failed to answer
workspace/diagnostic requests, that signal could be stranded, leaving
the agent stuck on 'Check project diagnostics' (reported with logs full
of 'Timeout during workspace diagnostics pull' and requests cancelled
after 120s).

Three hang paths in lsp_workspace_diagnostics_refresh:

1. Timeouts never resolved the completion signal. On
ConnectionResult::Timeout the loop just retried, holding the waiter
through up to 50 attempts x 120s each (~100 minutes) before the sender
was finally dropped.

2. Waiters could queue behind an already-hanging request. The refresh
channel has capacity 1; if the loop was mid-retry (e.g. the initial pull
at server startup was timing out), a newly enqueued waiter sat
unreceived until the entire retry cycle ended.

3. The request timeout was permanently disabled after the first partial
result. The timer raced progress_rx.recv() once and became pending()
forever if progress won, so a server that streamed one chunk and then
stalled hung the request indefinitely.

Fixes:

- On timeout, release all pending waiters (including ones that queued
mid-flight) with refreshed = false, so callers fall back to cached
diagnostics after at most one timeout period while the background loop
keeps retrying.

- Carry waiters as a Vec and absorb refresh requests queued during
backoff/in-flight requests into the current attempt instead of
serializing them behind it.

- Restart the timeout whenever a partial result arrives, turning it into
an inactivity timeout: streaming servers get unlimited total time while
they keep making progress, but a stalled stream now times out instead of
hanging forever.

Adds a regression test with a fake server that never answers workspace
diagnostic pulls, verifying the waiter resolves after the timeout; it
fails with 'Parking forbidden' (infinite hang) without the fix.

Closes FR-124

Release Notes:

- Fixed agents hanging indefinitely if an LSP server never responds to
diagnostics requests
2026-07-17 08:45:02 +00:00
Shuhei Kadowaki bce624a410 git_graph: Fix long commit message overflow in detail panel (#61163)
Follow-up to zed-industries/zed#60721.

The Taffy 0.12 upgrade exposed that the message height limit was applied
to its grid parent while percentage-sized children retained the Markdown
content's intrinsic height. Long messages therefore painted over the
changed-files summary instead of scrolling.

Move the height limit to the scroll container itself, matching the
commit view. Add a GPUI regression test that verifies the viewport stays
bounded, remains scrollable, and does not overlap the changed-files
list.

> On `main`:
<img width="697" height="873" alt="Screenshot 2026-07-17 at 14 59 21"
src="https://github.com/user-attachments/assets/51e6cc0e-aeac-4ad1-a6af-2120efcef901"
/>

---

Release Notes:

- N/A
2026-07-17 08:43:11 +00:00