Commit Graph
5168 Commits
Author SHA1 Message Date
Apoorva Verma b5e03c7b03 editor: Place added cursors by tab-expanded column (#61153)
with `hard_tabs: true` and `tab_size: 4`, shift-alt-down off a
tab-aligned column drops the cursor in the wrong spot:

```
      current.rgb.r         ˇ= p[0] >> 8;      <- cursor here
      residuals[run].rˇgb.r  = p[0] & 0xff;    <- lands here, not on the =
```

both `=` render at column 48 but sit at buffer columns 22 and 27, since
a different number of tabs pads each row. shift-alt-down is
`skip_soft_wrap: true`, which placed the cursor by utf16 column where a
tab counts as one.

so count the column with tabs expanded instead. still a column and not a
pixel position, so the buffer-column behaviour
`test_add_selection_skip_soft_wrap_option` pins doesn't change (without
tabs the expanded column *is* the buffer column). tried pixels first and
it breaks that test, since x is measured inside a wrapped segment.

heads up that the existing tests here all pass `Default::default()`,
which is `skip_soft_wrap: false` (the `default_true` only applies to
deserializing), so nothing covered the branch the keybinding actually
uses.

Closes #60752.

Release Notes:

- Fixed added cursors landing in the wrong column when using tabs to
align code
2026-07-21 06:22:51 +00:00
JaceandChristopher Biscardi c5e0fb8ffd search: Fix toggle soft wrap not working while the search bar is focused (#61150)
Closes #34698

The buffer search query input is itself an editor, so dispatching
`editor::ToggleSoftWrap` from the command palette while the search bar
had focus toggled soft wrap on the single-line query editor (with no
visible effect) and never reached the searched editor.

This intercepts the action on the search bar in the capture phase and
applies it to the active searchable item, the same way `ToggleFoldAll`
is already relayed. Focus stays in the search bar, so you can keep
typing your query. `Editor::toggle_soft_wrap` and
`Editor::soft_wrap_mode` become `pub` (matching
`fold_all`/`has_any_buffer_folded`, which the existing `ToggleFoldAll`
relay already uses).

Includes a regression test that fails without the fix: it deploys the
search bar, dispatches `ToggleSoftWrap` with the query editor focused,
and asserts the searched editor's wrap mode changes while focus remains
in the search bar.

Release Notes:

- Fixed `editor: toggle soft wrap` doing nothing when invoked while the
buffer search bar was focused

---------

Co-authored-by: Christopher Biscardi <chris@christopherbiscardi.com>
2026-07-21 06:14:52 +00:00
Ruslan Semagin 6b594a43b0 Show runnable task results in gutter (#61095)
# Objective

- Make runnable task results visible directly in the editor gutter after
running a test or task.
- This makes it easier to see whether the last run passed or failed
without looking at the terminal output.

## Solution

- Track the completion result for scheduled runnable tasks.
- Show the last runnable result in the gutter:
  - running task: accent play icon
  - successful task: success check icon
  - failed/cancelled task: error icon
- Apply the same status update path when running from the gutter play
button and from inline code lens actions such as `Run Test`.

## Testing

- Ran `cargo check -p editor -p workspace`.
- Ran `cargo test -p workspace
test_schedule_resolved_task_with_completion_reports_success`.
- Manually tested running a GPUI test from the gutter play button.
- Manually tested running a GPUI test from the inline `Run Test` code
lens.
- Verified the gutter icon updates after completion in both cases.

## 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:
<img width="1897" height="691" alt="before"
src="https://github.com/user-attachments/assets/614c2811-ee0a-43c0-8619-d0301836aa62"
/>

After:
<img width="1897" height="691" alt="after"
src="https://github.com/user-attachments/assets/a3db19f2-71e6-4c9b-824d-43a4f020a6b7"
/>

---

Release Notes:

- Improved runnable tasks by showing the last run result in the editor
gutter.
2026-07-21 05:36:42 +00:00
Sathwik Chirivelli ba1990441d git_ui: Show full files by default in solo diffs (#60989)
# Objective

Make solo diff views show the full file by default while preserving an
easy way to focus on changed hunks. This addresses a recurring request
across issues and pull requests for full-file context in single-file Git
diffs.

## Solution

- Initialize the solo diff with a singleton multibuffer so the entire
file is visible on open.
- Keep the existing toolbar toggle available for switching to
changes-only excerpts.
- Use the singleton path key when replacing excerpts so toggling remains
reliable.
- Preserve Git change indicators in the scrollbar; the editor generates
those markers for singleton buffers.

## Testing

- Ran `cargo fmt -p git_ui`.
- Ran `git diff --check`.
- Ran `cargo check -p git_ui --no-default-features` successfully.
- Manually reviewed the full-file and changes-only state transitions in
`SoloDiffView`.

## 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, solo diffs opened with only changed hunks and surrounding
context. They now open with the complete file, retain Git change
indicators in the scrollbar, and can still be toggled to changes-only
from the toolbar.

---

Release Notes:

- Improved solo diffs to show the full file by default while retaining
Git change indicators in the scrollbar.
2026-07-20 21:31:42 +00:00
Chris Biscardi 5c215b3613 Revert "editor: Add language detection for untitled buffers (#61201)" (#61351)
This reverts commit 690c7fac64.

# Objective

language detection is firing very often in channel notes, often picking
YAML instead of markdown, causing some language-detection flickering.

cc/ @amtoaer (author of the original PR)
2026-07-20 16:43:55 +00:00
ᴀᴍᴛᴏᴀᴇʀandMax Stevens 690c7fac64 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
Xin Zhao d735d22c25 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/c9e8e611dbc279afa0914d28c4d37ad07f38c03b/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/c9e8e611dbc279afa0914d28c4d37ad07f38c03b/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/c9e8e611dbc279afa0914d28c4d37ad07f38c03b/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/c9e8e611dbc279afa0914d28c4d37ad07f38c03b/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
ᴀᴍᴛᴏᴀᴇʀ 8e807731b7 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 04c247d1ca 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 1f99101eb0 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/0c51c7fd2481859e9da5c490ef8e41ddbcf1a341/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/0c51c7fd2481859e9da5c490ef8e41ddbcf1a341/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/0c51c7fd2481859e9da5c490ef8e41ddbcf1a341/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 bc61a30181 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 9ca3f21ada 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
Miguel Raz Guzmán Macedo ac5538b723 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
victorandCole Miller 80a1add64b 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
Jake AbendrothandCole Miller eb962794a3 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 2118a7c53a 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
Daan De Meyer 7d07d39f19 editor: Blink cursors only in the focused editor (#61086)
Every editor associated with a window observed window activation. The
handler enabled the blink manager for every editor, including hidden and
unfocused editors. Their independent 500 ms timers invalidated the
window out of phase and caused redundant full-window presents.

Window activation and deactivation are already represented as focus
transitions by GPUI: an inactive window has an empty effective focus
path. Remove the redundant activation observer and rely on the editor
focus and blur handlers to stop blinking on deactivation and restart it
only for the editor that owns focus on activation.

In a 40-second idle diagnostic run before this change, the steady-state
tail repeatedly contained invalidations from one or two editors per
frame. After the change, no unfocused-editor invalidations appeared.
Bounded scrollbar fades and visible activity animations remain
unchanged.

Add a regression test with focused and unfocused editors that covers
activation, deactivation, and reactivation.

Release Notes:

- Fixed cursors blinking in unfocused editors, reducing idle redraws.

---------

Signed-off-by: Daan De Meyer <daan@amutable.com>
2026-07-16 11:43:27 +00:00
Aliaksandr ZhyburtovichandNathan Sobo 9dfdaa62b7 editor: Preserve non-breaking whitespace during rewrap (#59893)
## Objective

Prevent rewrap from breaking at whitespace that Unicode classifies as
non-breaking.

The original approach, prompted by #59664, treated every non-ASCII
whitespace character as unbreakable. Unicode classifies `U+2009 THIN
SPACE` as breakable and `U+202F NARROW NO-BREAK SPACE` as its
non-breaking counterpart.

## Solution

- Treat `U+00A0 NO-BREAK SPACE`, `U+2007 FIGURE SPACE`, and `U+202F
NARROW NO-BREAK SPACE` as part of the surrounding word
- Keep thin spaces, em spaces, and other Unicode breaking spaces as
line-break opportunities
- Cover all three non-breaking whitespace variants in tokenizer and
wrapping tests

## Testing

- `cargo test -p editor rewrap::tests`

Release Notes:

- Fixed rewrap breaking lines at non-breaking spaces.

---------

Co-authored-by: Nathan Sobo <nathan@zed.dev>
2026-07-15 22:17:51 +00:00
David 63692b8b47 search: Add LSP location pickers for references, definitions, and diagnostics (#59838)
# Objective

Closes #59829

Provide a filterable, preview-backed picker for LSP results as an
alternative to the multi-buffer view, for references, definitions,
implementations.

## Solution

Update the 3 existing LSP actions (definitions, implementations, find
all references) to add a `open_results_in` parameter which accepts
either `multi_buffer` (default) or `picker` to show the results in a
filterable picker with preview. This behavior can be configured globally
in the settings via `lsp_results_location`.

UX:

- The 3 existing LSP actions each accept a `open_results_in` parameter
so that each action can be configuring individually with a custom
keybind
- The `lsp_results_location` global setting can be used to set a default
behavior with `open_results_in == None`
- Go to definition falls back to find all references (if configured) on
empty results which is consistent with the non-picker path
- Results are grouped by file; each row shows the line number and the
syntax-highlighted source line with the match emphasized.
- Typing filters by line text or path; the preview updates with the
selection.
- Enter/click opens the selection, `cmd/ctrl-enter` opens it in a split,
and re-invoking the command toggles the picker closed.
- Empty results show a toast so the command never silently does nothing.
- Note: the new pickers do not open on cmd-click, only when invoked via
the command palette or keybind

## Testing

- No automated tests yet — holding for first-round feedback on the
approach and UX before adding tests.

## Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] 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
- [ ] Performance impact has been considered and is acceptable

## Showcase


https://github.com/user-attachments/assets/41538f23-9b54-4dfc-bfa7-a61564a675a8

---

Release Notes:

- The find all references, go to definitions, and go to implementations
LSP actions can be configured to open results in a picker with preview
instead of a multibuffer.
2026-07-15 14:36:43 +00:00
Ben Kunkle eb0e870042 Classify edit prediction lifecycle triggers (#60983)
# Objective

Closes EP-89

- Replace ambiguous `Other` edit prediction telemetry for known editor
lifecycle events.

## Solution

- Classify editor creation, provider changes, user information changes,
Vim mode changes, and settings changes through the existing trigger
pipeline.

## Self-Review Checklist:

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

---

Release Notes:

- N/A
2026-07-15 13:14:36 +00:00
Smit Barmase 3565c49dad terminal_view: Fix cursor column for non-ASCII lines when opening path-like targets (#61036)
Found this while looking into a markdown preview issue. Clicking a
`path:row:column` target in the terminal treated the column as a byte
offset, so on lines with non-ASCII characters the cursor landed at mid
codepoint.

The real fix is just 3 lines and the rest is a refactor that extracts
the open and navigate logic so it can be reused later for cases like
markdown preview.

Release Notes:

- Fixed the cursor landing at the wrong column when clicking a
`path:row:column` link in the terminal for lines containing non-ASCII
characters.
2026-07-15 10:05:32 +00:00
Lukas Wirth f181a2f47b Split out RelPath into a separate crate (#61029)
This is necessary to remove some `util` dependencies from crates, as
well as better sharing for our projects. This also includes the WIP
AbsPath abstraction as well as some bug fixes from internal tooling.


Release Notes:

- N/A or Added/Fixed/Improved ...
2026-07-15 08:33:25 +00:00
Kirill Bulatov ef2430c8f3 Properly notify on inline diagnostics toggle (#60978)
Closes https://github.com/zed-industries/zed/issues/60959

Release Notes:

- Fixed inline diagnostics not instantly [dis]appearing after toggling
2026-07-14 16:57:03 +00:00
Kirill Bulatov 7cf50a771f Add more context (#60913)
Started an old Zed version with old db entry which resulted in 0 agent
panel working, only showing me there and in logs "project path not
found".

Fixed by removing the corresponding `db` subdirectory, but decided to
make the log entries a bit more useful.

Release Notes:

- N/A
2026-07-14 10:09:31 +00:00
Ruslan SemaginandDanilo Leal 97110fd5a1 Show tag names in git blame tooltips (#60757)
Fetch tag names for commits included in blame data and pass them through
the blame rendering path. Render tag names as chips in the blame hover
tooltip and expanded blame popover. Tag lookup is best-effort, so blame
still renders if tag lookup fails.

> Note: Tag names are currently only fetched for local repositories. For
remote projects (SSH) and collab sessions, blame data travels over the
`BlameBufferResponse` proto message, which doesn't carry tag names yet.

  ## Testing

- `cargo test -p git
test_parse_tag_names_for_lightweight_and_annotated_tags`
  - `cargo check -p git_ui`
  - `cargo check -p editor`
  - `cargo check -p project`

  Manual testing:
  - Opened `git: blame` on a file with a tagged commit.
- Verified tag chips are shown in the blame hover tooltip and expanded
popover.

  ## 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:
<img width="1655" height="660" alt="before"
src="https://github.com/user-attachments/assets/dbefd729-f8df-48a9-8249-83c93518fe76"
/>

After:
<img width="1655" height="660" alt="after"
src="https://github.com/user-attachments/assets/2c1097de-b268-45d9-9d13-0f3e06058603"
/>

---

Release Notes:

- Git: Made tags visible in Git blame tooltips.

---------

Co-authored-by: Danilo Leal <daniloleal09@gmail.com>
2026-07-14 01:21:38 +00:00
Apoorva VermaandKirill Bulatov 56ab1c4825 project: Report formatter failures in the status bar again (#60839)
set a formatter that fails (`"formatter": {"external": {"command":
"false"}}`), save, and you get nothing. it just goes to the log, the
"Formatting failed" indicator never shows.

#51605 made the formatter loop log-and-continue instead of bailing (so
unrelated edits don't get reverted, #51490). downside was the pipeline
always returned Ok after that, so the failure flag the indicator reads
always got wiped. this brings back failures from formatters you actually
configured. auto ones stay quiet when they're not around, so no prettier
installed = still a no-op.

only explicit failures show up, bit narrower than before #51605. can
widen it to auto ones too if you want, one line.

Fixes #59988.

Release Notes:

- Fixed formatter failures not showing the "Formatting failed" status
bar indicator

---------

Co-authored-by: Kirill Bulatov <kirill@zed.dev>
2026-07-13 20:24:53 +00:00
Finn Eitreim 78c0f2522a editor: Fix incorrect inlay hint selection behavior (#60912)
# Objective

Fixes #48141

The issue is that there are certain situations where an Inlay hint,
specifically hints that appear to the left of whatever item they are
referring to, e.g. function argument hints, will be selected
incorrectly.


https://github.com/user-attachments/assets/b6d60bad-6999-481b-a1c7-420d3ee113f8

As you can see in the video, in both a modal and non-modal editor, as
soon as you include `(` (or the empty space between the first and second
argument) the hint gets highlighted as well.

## Solution

It is really important to note here that there is no issue with the
actual selection semantics, inlay hints don't get truly selected in the
sense that they don't count as buffer text and if you e.g. copy a
selection with a hint in it it doesn't get copied. A second thing to
note is that a fix that looks good for modal editing might not look good
for regular editing, thats largely what sank the previous attempt to fix
this issue (#51219).

This video is from #51219, but earlier versions of my fix suffered from
the exact same issue.


https://github.com/user-attachments/assets/16452530-1918-47da-9fd4-87c285284959

The cursor behavior for an active selection in a non-modal editor and
when there isn't a selection are different, and right now the behavior
is wired for the non-selection case, the solution to this is to separate
how things display with a selection from the other behavior. !I do not
change the non-selection behavior in any way!

Inlay hints at the boundary of a selection should be excluded, but hints
inside of a selection should be part of the contiguous selection. We can
reuse the `DisplayPointConverter` to do this. My original solution was
to use `isomorphic_display_point_ranges_for_buffer_range`, which maps a
buffer offset range into a `DisplayPoint` range that excludes Inlays,
except it actually maps to potentially several ranges, all the buffer
text *in between* inlay hints. By just taking the start of the first
sub-range, and the end of the last, we get the correct range that we are
looking for. The function I added,
`contiguous_display_point_range_for_buffer_range` basically just does
exactly that, and cut out all the extra work of creating a bunch of
intermediate ranges if it was a large selection with lots of inlays.

Then we can set the cursor head based on this range, this gives the
correct behavior for non-vim mode cursors, the vim mode cursor is
handled by other code after we set that anyway, so vim mode behavior is
unchanged.

These code changes are in `SelectionLayout::new`
```rust 
        let buffer_snapshot = map.buffer_snapshot();
        let point_selection = selection.map(|p| p.to_point(buffer_snapshot));
        let display_selection = point_selection.map(|p| p.to_display_point(map));
        let mut range = display_selection.range();
        let mut head = display_selection.head();
        if !line_mode {
            let offset_range = point_selection.start.to_offset(buffer_snapshot)
                ..point_selection.end.to_offset(buffer_snapshot);
            if let Some(contiguous_range) =
                map.contiguous_display_point_range_for_buffer_range(offset_range)
            {
                range = contiguous_range;
                // Keep the cursor attached to the highlight boundary; the
                // anchor-bias display position may sit on the far side of a
                // boundary inlay the highlight excludes.
                head = if selection.reversed {
                    range.start
                } else {
                    range.end
                };
            }
        }
```

Heres the new behavior:


https://github.com/user-attachments/assets/cbbd53d6-bbea-4c50-91b5-23eaccd5d9d7

## Testing

added `test_selection_layout_around_inlay`, that fails on main currently
and passes with my changes. As far as manual testing the setup is pretty
easy, this is generally pretty language agnostic and can be tested
anywhere with function parameter hints.

## 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 rendering issues with selections over inlay hints.
2026-07-13 18:59:49 +00:00
Apoorva VermaandKirill Bulatov 1c5b2b815b Use buffer line numbers when copying file locations (#60781)
# Objective

Fixes #54250

`editor: copy file location` copies the row you're on in the
multi-buffer, not the row in the actual file. In a git diff view with
collapsed lines it copies the wrong line number.

## Solution

It read the rows straight off the selection, which is in multi-buffer
coordinates. `ClipboardSelection::for_buffer` already handles this with
`range_to_buffer_range`, so I used the same thing. Path and line now
come from the same buffer.

`range_to_buffer_range` returns nothing when the selection ends in a
different buffer than it starts in, which you can do in a git diff view.
Rather than copy nothing, it falls back to the cursor's buffer.

## Testing

Three tests: a multi-buffer excerpt, a selection dragged across two
files, and a plain single-file editor. The multi-buffer ones fail on
main; the singleton one passes either way, so normal editors are
unaffected.

## 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 `editor: copy file location` copying the wrong line number in
multibuffers
([#54250](https://github.com/zed-industries/zed/issues/54250)).

---------

Co-authored-by: Kirill Bulatov <kirill@zed.dev>
2026-07-13 10:51:59 +00:00
Khôi TranandSmit Barmase 715557fe51 editor: Add support for pasting images in Markdown (#58588)
Self-Review Checklist:

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

Closes #18112

Release Notes:

- Added support for pasting images from clipboard into Markdown files

---------

Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com>
2026-07-13 09:12:47 +00:00
Apoorva Verma 869d6eae22 language: Autoclose nested brackets in plain text (#60841)
in a plain text file, cursor before a closing bracket, type an opening
one and nothing autocloses. `anything|)` + `[` gives `anything[|)` not
`anything[]|)`. fine in js/css/py.

autoclose checks the language's `autoclose_before` set. every language
sets one, plain text didn't, so a closing bracket ahead of the cursor
killed it. gave it `)]}`.

went `)]}` not the usual `;:.,=}])>` since plain text only has brackets.
`.typ` (Typst) is a separate extension, needs the same fix there.

Fixes #60560.

Release Notes:

- Fixed nested brackets not auto-closing in plain text files
2026-07-12 21:46:59 +00:00
Yifeng Xuandpeakxy 08359123ac Fix “Open file in project" option in the right-click menu not working (#60807)
# Objective

Fix file header context menu actions in multi-file Git history diffs.
Previously, `Open File in Project` worked for the first file but did
nothing for subsequent files.

Fixes #60790

## Solution

Include the buffer ID in each file header context menu's GPUI element
ID. This prevents multiple file headers in split diff views from sharing
the same menu state.

## Testing

- Ran `cargo check -p editor --lib`.
- Ran `cargo fmt --package editor -- --check`.
- Reviewers can test by opening a multi-file commit from Git Panel →
History in split diff mode, then using `Open File in Project` on the
second and subsequent file headers.


https://github.com/user-attachments/assets/46fa4e15-60ac-4ae3-9a73-a89c7f107cb0

## 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 opening project files from context menus in multi-file Git
history diffs.

Co-authored-by: peakxy <2465549609@qq.com>
2026-07-12 21:08:20 +00:00
Pranav NedungadiandChristopher Biscardi 60099a06df git_ui: Add restore buttons to unstaged diff view (#60639)
The unstaged diff view introduced in the partially staged changes commit
only had a Stage button but no Restore option. This adds:

- A per-hunk Restore button in the inline hunk controls (disabled for
new files)
- A Restore button in the toolbar for selected hunks
- A Restore All button in the toolbar to discard all unstaged changes
- A restore method override on UnstagedDiffDelegate for the Restore
action

Release Notes:

- Added restore buttons to the unstaged diff view for discarding
unstaged changes.

# Objective
New unstaged and staged diffs were added in #46541 . However for
unstaged changes, only option available is to stage a change. It would
also be a common use case to restore the changes. (Like how it is done
in uncommitted changes).

## Solution
- A per-hunk Restore button in the inline hunk controls (disabled for
new files)
- A Restore button in the toolbar for selected hunks
- A Restore All button in the toolbar to discard all unstaged changes
- A restore method override on UnstagedDiffDelegate for the Restore
action

## Testing
Tested in locally and ensured both features work

## Self-Review Checklist:

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

## Showcase
<img width="1141" height="635" alt="Screenshot 2026-07-09 at 9 00 47 AM"
src="https://github.com/user-attachments/assets/b1d3f091-9f1d-49c6-87e6-9efad25e62dd"
/>

## Note
I am still learning rust bit by bit. Please let me know if something is
massively wrong. This is assisted by AI but reviewed by me with best of
my knowledge.

---

Release Notes:

- Added restore buttons to the unstaged diff view for discarding
unstaged changes.

---------

Signed-off-by: Pranav <pranav10121@gmail.com>
Co-authored-by: Christopher Biscardi <chris@christopherbiscardi.com>
2026-07-12 13:39:09 +00:00
Mikayla Maki 9c3273201c gpui: Add mobile/touch API surface (#60496)
TODO:

- [ ] Remove slop comments
- [ ] Review APIs in detail

# Objective

- This PR aims to add official mobile API surfaces to GPUI

## Solution

- This PR cross references several internal experiments to come up with
a general cross-platform abstraction for core input mechanisms, but
defers actual implementations to later. These are intended to be a
common base to build off of.

## Testing

- Yes, as mentioned above with external experiments

## Self-Review Checklist:

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

---

Release Notes:

- N/A
2026-07-11 22:14:52 +00:00
Lukas Wirth 9cdaff1492 editor: Fix panic removing blocks in split diff with companion edit at EOF (#60445)
BlockMap::sync unwrapped the transform cursor for every edit, assuming
each edit's old.start lands strictly inside the old transform tree. The
companion (split-diff) branch of sync can compose an edit anchored at
the trailing boundary of the old transforms, leaving the cursor past the
end of the tree and aborting the process on the None unwrap. Only bind
the transform when there are rows preceding the edit.

Fixes ZED-9V4.
Closes FR-113


Release Notes:

- N/A or Added/Fixed/Improved ...
2026-07-09 09:20:39 +00:00
Lukas Wirth 0bc9c99f00 Invalidate hover state when a multibuffers paths change (#60443)
Fixes a panic when multibuffer paths change under a cursor hover
Fixes ZED-9W1
Closes FR-112

Release Notes:

- N/A or Added/Fixed/Improved ...
2026-07-09 09:20:36 +00:00
Todd L Smith 57261fef89 editor: Add actions to move between comment paragraphs (#58353)
Jump the caret straight to the next/previous block of prose comments —
like paragraph motion, but for comments.

The motivating workflow: reflowing a file's comments with `editor:
rewrap`. Today that means reaching for the mouse to click into each
comment block scattered through the file, or using other cursor motions
and undershooting or overshooting the target. With these two actions you
can step from one comment paragraph to the next, `rewrap`, and repeat —
reflowing every comment in a file without ever touching the mouse. It's
also handy for skimming a heavily-documented file: hop from doc comment
to doc comment without manually scrolling past the code in between.

Adds two editor actions:

- `editor::MoveToNextCommentParagraph`
- `editor::MoveToPreviousCommentParagraph`

Both move the caret to the first non-whitespace character of the
next/previous *comment paragraph*. They have no default keybinding and
are available from the command palette ("editor: move to next/previous
comment paragraph").

### What counts as a comment paragraph

A comment paragraph is a run of consecutive comment lines. A line is a
comment line when its **first non-whitespace character is in a `comment`
syntax scope** and the line contains prose (at least one alphanumeric
character). This is determined from the syntax tree
(`language_scope_at(...).override_name()`), the same mechanism `rewrap`
and comment folding already use, so it behaves correctly without
per-language string matching:

- **End-of-line comments preceded by code are ignored** — on `let x = 1;
// note` the first non-whitespace character is code, not a comment, so
the line is not a paragraph line.
- **`//` inside a string literal is ignored** — its scope is `string`,
not `comment`.
- **Blank/divider comment lines separate paragraphs** — a bare `//` or
`// -----` (no prose) acts as a separator, so you can hop between
paragraphs *within* one comment block as well as across blocks.

Both directions always move to a paragraph *other* than the one the
caret is in: when the caret is inside a paragraph, the whole current
paragraph is skipped, so `Prev` lands on the previous paragraph's start
rather than the current paragraph's own start.

### On the autoscroll

These two actions scroll the destination near the top of the viewport
(`Autoscroll::top_relative`) rather than using the default `Fit`
strategy that sibling motions use. This is deliberate and specific to
the feature: you are jumping to the **start** of a comment paragraph
that extends *downward*, so biasing the destination toward the top keeps
the whole paragraph visible after the jump. This matters for the rewrap
workflow above — you want to see the full comment you are about to
reflow, and the reflow itself changes the paragraph's line count. With
the default `Fit`, repeated forward jumps creep the caret to the bottom
edge and leave long paragraphs cut off below the fold — the opposite of
what this motion is for. Happy to revisit the exact strategy/offset if
you'd prefer consistency with the other motions.

### Tests

Two tests in `editor_tests.rs` (using a real grammar + comment override
query):

- `test_move_to_next_and_previous_comment_paragraph` — full
forward/backward round trip, covering blank comment-line separators,
code separators, trailing comments, and the no-more-paragraphs stop.
- `test_move_to_previous_comment_paragraph_skips_current_paragraph` —
`Prev` from mid-paragraph skips to the previous paragraph, and stays put
when there is no previous paragraph.

---

Self-Review Checklist:

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

- Added `editor::MoveToNextCommentParagraph` and
`editor::MoveToPreviousCommentParagraph` actions to move the caret
between comment paragraphs
2026-07-09 05:49:09 +00:00
G36maidandKirill Bulatov b9f3396b68 Add support for format_on_save only changed lines (#49964)
## Summary

Introduces `format_on_save` variants that format only modified lines,
limiting formatting to lines changed since the last commit. This
prevents massive diffs when editing legacy codebases. Aligns with VS
Code's `editor.formatOnSaveMode` naming:

- `"modifications"` — formats only git-diffed lines. Requires source
control; skips formatting if no diff is available.
- `"modifications_if_available"` — formats only git-diffed lines,
falling back to full-file formatting for untracked files, when source
control is unavailable, or when the LSP does not support range
formatting.

Also supports importing equivalent VS Code settings
(`formatOnSaveMode`).

This PR uses the range-based whitespace/newline infrastructure from the
dependency PR above.

## Changes


<details>
<summary><b>New settings, modified ranges computation, VS Code
import</b></summary>

### New settings (`language.rs`, `default.json`, `all-settings.md`)

Two new `FormatOnSave` variants: `Modifications` and
`ModificationsIfAvailable`.

### Modified ranges computation (`items.rs`)

- `compute_format_decision()` — reads `format_on_save` setting across
all buffers, determines whether to use ranged formatting (`Ranges`),
full formatting (`Full`), or skip (`Skip`).
- `compute_modified_ranges()` — extracts modified line ranges from git
diff hunks via `BufferDiffSnapshot`.
- `is_empty_range()` — helper to detect deletion-only hunks that produce
no formatable content.

The `save()` method calls `compute_format_decision()` and dispatches
accordingly.

### Modifications mode in `lsp_store.rs`

- Adds `FormatOnSave::Modifications |
FormatOnSave::ModificationsIfAvailable` to the formatter selection match
arm.
- `ModificationsIfAvailable` falls back to full-file formatting when
ranged formatting produces no results.

### VS Code settings import (`vscode_import.rs`, `settings_store.rs`)

Imports `editor.formatOnSaveMode` mapping:
- `"modifications"` → `FormatOnSave::Modifications`
- `"modificationsIfAvailable"` →
`FormatOnSave::ModificationsIfAvailable`
- `"file"` → `FormatOnSave::On`

</details>

## Tests

- `test_modifications_format_on_save` — basic modifications mode
formatting with dirty buffer
- `test_modifications_format_no_changes` — clean buffer triggers no
formatting
- `test_modifications_format_lsp_no_range_support` — LSP without range
formatting skips entirely for `Modifications`
- `test_modifications_format_lsp_returns_empty_edits` — empty edits
handled gracefully
- `test_modifications_format_multiple_hunks` — two non-adjacent edits
produce two separate range formatting requests

---

Self-Review Checklist:

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


Closes #16509
Depends on #53942

Release Notes:

- Added `modifications` and `modifications_if_available` options to
`format_on_save`, which format only git-changed lines instead of the
entire file
- When using modifications mode, `remove_trailing_whitespace_on_save`
and `ensure_final_newline_on_save` are also scoped to changed lines,
preventing unwanted diff jitter in legacy codebases
- Added support for importing VS Code's `editor.formatOnSaveMode`
setting

---------

Co-authored-by: Kirill Bulatov <kirill@zed.dev>
2026-07-08 16:53:11 +00:00
TwoClocksandKirill Bulatov 029bf2f284 Make editor::LineUp & editor::LineDown honor vertical_scroll_margin like vim::LineUp & vim::LineDown (#52057)
## Context

This is an implementation of this feature:
https://github.com/zed-industries/zed/discussions/49821

Although, I'd argue it's a bug fix, not a feature.

Either way : This copies the window scroll logic from the `vim` mode
versions with out all the extra logic for visual mode.

Could refactor the common logic out of the vim code and make it common.
But that seems like a bigger PR. Happy to take a stab at it if that's
what you prefer.
Could also add new commands for the new behavior if you prefer. I didn't
do that, because it seems like more clutter in the commands, and my
belief that the existing behavior is a bug. But happy to do that if you
prefer.

## How to Review

creates new function `scroll_screen_with_cursor_margin` in `scroll.rs`
wires up editor::LineUp/LineDown to new function in `elements.rs`
adds a test in  `editor_tests.rs`

## Self-Review Checklist

<!-- Check before requesting review: -->
- [X] I've reviewed my own diff for quality, security, and reliability
- [X] Unsafe blocks (if any) have justifying comments
- [X] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [X] Tests cover the new/changed behavior
- [X] Performance impact has been considered and is acceptable

Release Notes:

- editor::LineUp/LineDown commands now honor vertical_scroll_margin
(same as vim::LineUp/LineDown)

---------

Co-authored-by: Kirill Bulatov <mail4score@gmail.com>
2026-07-08 16:37:08 +00:00
Neel 86b2831c7c editor: Use raw head selection for rename (#60594)
Follow up to https://github.com/zed-industries/zed/pull/55542, which
reused the shifted offset for the rename input's *initial selection*,
cutting it one character short.

<img width="524" height="512" alt="image"
src="https://github.com/user-attachments/assets/37032614-2cfd-4ad4-9005-f2eac57924a1"
/>
<img width="435" height="158" alt="image"
src="https://github.com/user-attachments/assets/7b1b9c52-08d6-48ce-928a-873f6e175f65"
/>

---

Release Notes:

- Fixed symbol rename in vim mode omitting the last character of the
symbol out of the rename input's initial selection
2026-07-08 14:19:58 +00:00
Guilherme TavaresandKirill Bulatov 385e9c68ae Suggest language extensions for untitled buffers (#55263)
Fixes #53527.

## Summary

- Suggest `untitled.<extension>` when saving an untitled editor buffer
with a selected non-Plain Text language.
- Preserve the existing title-based suggestion for existing files, Plain
Text buffers, and buffers without a language extension.
- Add a regression test for an untitled Rust buffer suggesting
`untitled.rs`.

## Testing

- `mise exec rust@1.95.0 -- cargo fmt --check -p editor`
- `mise exec rust@1.95.0 -- cargo test -p editor
test_suggested_filename_uses_language_extension_for_untitled_buffer
--lib`

## Suggested .rules additions

None.

Release Notes:

- Fixed Save As suggestions for untitled buffers with a selected
language.

---------

Co-authored-by: Kirill Bulatov <kirill@zed.dev>
2026-07-08 12:29:04 +00:00
Miguel Raz Guzmán Macedo bc3c9422f4 Use more .array_windows::<N>() (#58877)
- [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

The fight against entropy continues...

Release Notes:

- N/A or Added/Fixed/Improved ...
2026-07-08 12:10:32 +00:00
Matt Goodanddino 950ec7943f editor: Decode escaped characters in hover popover links (#55973)
Decodes url escape sequences in hover preview `file:///` links like
escaped
spaces in the file path.

I'm working on an LSP and happened to be working with some files in a
directory with spaces. When adding Markdown links with `file:///` the
`%20` escape for spaces was being included verbatim in the path that Zed
tried to open.

I'm reusing the lines from `markdown_preview_view.rs` for decoding. In
the existing tests I don't see coverage for `file:///` links. If you'd
like some tests for this can you point me to any examples to start from?

Self-Review Checklist:

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

Release Notes:

- Fixed decoding spaces and other escaped characters in `file://` links
used in hover popovers

---------

Co-authored-by: dino <dinojoaocosta@gmail.com>
2026-07-08 09:01:58 +00:00
Smit Barmase 001bda1a46 project: Fix ref-match rust completions dropping the leading & (#60521)
Closes #56973, Follow-up for
https://github.com/zed-industries/zed/pull/56976

When a completion's `additionalTextEdits` contained a zero-width
insertion touching the edge of the primary edit, the overlap check
treated it as overlapping and silently skipped it. This broke
rust-analyzer's ref-match completions (`&foo`), which deliver the `&` as
a zero-width additional edit at the primary edit's start (#56973). The
same root cause previously broke auto-imports at the very start of a
file (#26136), which was worked around in #37746 with a special case for
edits at position (0, 0).

This PR replaces that special case with a general rule: a zero-width
additional edit only overlaps the primary edit when it falls strictly
inside it. i.e. touching the boundary is fine.

This one check handles both the file-start auto-import case and the `&`
ref-match case, so the (0, 0) workaround from #37746 is removed.
Non-insertion edits still go through the original overlap check from
#1871.

Added three regression tests:
- the file-start auto-import (#26136)
-  the `&` insertion at the primary edit's start (#56973)
- overlapping edits being skipped while non-overlapping ones apply
(general skip case)

Release Notes:

- Fixed rust-analyzer completions like `&some_var` inserting only the
variable name and dropping the leading `&` when accepted.
2026-07-07 07:49:53 +00:00
c31b2b0dc7 Git partially staged changes (#46541)
This PR explores the addition of a new feature and UI to improve
visibility into partially staged commits.

Currently, the Git panel shows tracked and untracked changes, but it
does not clearly distinguish between staged and unstaged changes.

As a result, it’s difficult to quickly see which changes are not staged
in the current UI. Both staged and unstaged changes are combined into
the `Uncommitted Changes` multibuffer. This developer experience differs
from other editors, most notably VS Code; which presents separate Staged
Changes and Changes lists.

### Staged and unstaged diffs in multibuffers

This PR introduces an alternative UI for unstaged changes that aligns
with the overall Zed experience. Instead of showing changes on a
per-file basis, staged and unstaged diffs are each displayed in their
own multibuffers, similar to how `Uncommitted Changes` currently works.

For example the following screenshot shows the current `Uncommitted
Changes` on the left, the `Staged Changes` in the middle and the
`Unstaged Changes` buffer on the right for comparison

<img width="1408" height="859"
src="https://github.com/user-attachments/assets/aa709f7a-041d-4cb1-95d6-84c0f5fff688"
/>

### Indicators/interactions

The new multibuffers can be opened in two ways:

1. Via a new `U` chip, which appears when a file has unstaged changes
2. Via new menu options

(See screenshots below for both interaction paths.)


<table>
  <tr>
    <td style="text-align: center; vertical-align: top;">
      <p>via the chip</p>
      <img
        height="400"

src="https://github.com/user-attachments/assets/3ef69f02-b787-499c-959a-25f50b3728e8"
        alt="Via the chip"
      />
    </td>
    <td style="text-align: center; vertical-align: top;">
      <p>via the menu</p>
      <img
        height="400"

src="https://github.com/user-attachments/assets/f5be8b6d-ccdc-4420-bd29-75570b558016"
        alt="Via the menu"
      />
    </td>
  </tr>
</table>

### Design goals
- minimally intrusive UI changes (small new badge and menu items)
- adhere by Zed'ism (use multibuffer where possible)
- avoid disabling any current interactions (Uncommitted Changes ui is
unchanged)
- avoid introducing an app level view mode (no new settings needed)

### Experience goals
- make it easy to see what changes are not staged
- make it easy to see that a file has unstaged changes (avoid developers
accidently leaving out changes in a commit; a personal issue that I have
when using Zed)
- elegantly handle large file's unstaged changes (follows the same
collapse and expanding seen in `Uncommitted Changes`)

### How to try

- Clone the repo and run `cargo run`
- Make a change to a file and stage it
- Make another change to the file (the `U` indicator will appear)
- Click the `U` to see the unstaged view

### Open questions/rough edges
- [ ] determine if this user experience is useful for others
- [ ] ensure all interactions work as expected (response to all update
cases)

In general I'm really interested in hearing the community's feedback
about this interface, more than happy to make any changes or explore a
different solution!

### Related issue:
- https://github.com/zed-industries/zed/pull/36646
- https://github.com/zed-industries/zed/issues/26560

Release Notes:

- Support partially staged commit multibuffers via a staged and unstaged
changes view.

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Cole Miller <cole@zed.dev>
2026-07-07 06:55:29 +00:00
davidhi7andSmit Barmase 98fe76caad editor: Fix completion labels not being rendered completely (#56976)
PR https://github.com/zed-industries/zed/pull/45892 changed the logic
for rendering completion labels and divided rendering up into the "main"
part (consisting of the completion's `filter_range`) and "details" part
(everything after `filter_range`), but no longer renders text that comes
before the `filter_range`. This text is probably not relevant in too
many cases but makes some Rust completions unclear and ambiguous, as can
be seen in this example:

Without this change:
<img width="1262" height="313" alt="Image"
src="https://github.com/user-attachments/assets/dcdd9da4-c449-445d-b379-771b368c3778"
/>

With this change:
<img width="1328" height="376" alt="grafik"
src="https://github.com/user-attachments/assets/05fdaf95-7a18-4d50-8e3b-35be10d9a1ef"
/>

Self-Review Checklist:

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

Closes #56973

Release Notes:

- Fix completion labels not being rendered completely

---------

Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com>
2026-07-06 21:22:14 +00:00
Danilo Leal f16b46419d Improve diff tabs toolbar design (#60464)
This PR adds a bunch of design improvements to the toolbar of (tab)
views that display diffs: the uncommitted changes, branch diff, and
agent diff tabs. This involves adjusting spacing, sizing, and other
small tweaks across all of these views, including touching up the
divider component API a little bit, adjusting Git icons design, adding
diff stat numbers to the uncommitted changes tab so its consistent with
the others, and more (e.g., moving the split buttons into its own
component to ensure they look the same across all uses). Ended up also
going on a slight de-tour to make all uses of the split button in the
Git panel consistent design-wise.

All in all, this is just tidying up the design of all of these surfaces
that are all relatively similar.

| Branch Diff | Uncommitted Diff | Single-file Diff | Git Panel |
|--------|--------|--------|--------|
| <img width="800" alt="Screenshot 2026-07-06 at 11  25@2x"
src="https://github.com/user-attachments/assets/4ebf87e7-c52d-41d9-9de3-7944125114a1"
/> | <img width="800" alt="Screenshot 2026-07-06 at 11  25 2@2x"
src="https://github.com/user-attachments/assets/51ccd2eb-904b-455a-a708-b4cb50b3a7cb"
/> | <img width="800" alt="Screenshot 2026-07-06 at 11  26@2x"
src="https://github.com/user-attachments/assets/6ae7df68-d1bd-4d36-a250-ba16e43c4e8e"
/> | <img width="800" alt="Screenshot 2026-07-06 at 11  26 2@2x"
src="https://github.com/user-attachments/assets/e032bc60-4551-41f0-b578-90ed305167c2"
/> |

Release Notes:

- Added diff stat numbers to the uncommitted changes view.
2026-07-06 15:46:44 +00:00
João SoaresandChris Biscardi c4a9b1aa4b Fix blame hover popover not showing on first trigger when inline blame is disabled (#50769)
● Closes #50285

## Summary

When `inline_blame` is disabled in settings and `editor::BlameHover` is
triggered,
the blame popover fails to appear on the first invocation because
`start_git_blame`
kicks off an async task to fetch blame data, but `blame_hover`
immediately tries to
read that data synchronously before it's available.

This fix registers a one-shot observation on the blame entity when it's
freshly
created, so the popover is shown once blame data has finished
generating.

Before you mark this PR as ready for review, make sure that you have:
- [x] Added a solid test coverage and/or screenshots from doing manual
testing
- [x] Done a self-review taking into account security and performance
aspects
- [ ] ~Aligned any UI changes with the [UI
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)~
(No UI changes)

## Videos:
### Before:

https://github.com/user-attachments/assets/d2ca4f8e-8186-49af-9908-5a82bfca0de2


Ps: pressed the keybind two times

### After:

https://github.com/user-attachments/assets/08575cd9-2bbc-462d-92fa-f0e7ef23d8d6



## Release Notes:

- Fixed blame hover popover not appearing on first trigger when inline
blame is disabled (#50285)

---------

Co-authored-by: Chris Biscardi <chris@christopherbiscardi.com>
2026-07-06 08:51:35 +00:00
Anthony Eidandzed-zippy[bot] 262fb9ba2a Show per-file diff stat in multibuffer headers (#60299)
Renders the per-file added/removed line counts (already tracked per
buffer by the multibuffer) in each diff multibuffer header, matching the
overall stat shown in the branch diff toolbar.

### Before
<img width="1624" height="1061" alt="Screenshot 2026-07-02 at 11 50 42
AM"
src="https://github.com/user-attachments/assets/3e46a90c-a4e1-4b72-8ec9-80931a7e4a9a"
/>

### After
<img width="1624" height="1061" alt="Screenshot 2026-07-02 at 12 03 58
PM"
src="https://github.com/user-attachments/assets/25900790-82f5-44e9-9a3b-731a3090f23e"
/>


Release Notes:

- Improved diff multibuffer headers to show per-file added/removed line
counts

---------

Co-authored-by: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>
2026-07-03 17:55:24 +00:00
saberoueslatiandDanilo Leal e1ec575d3f editor: Update gutter hover tooltip on modifier changes (#58880)
## Context

The gutter hover button can represent either adding a breakpoint or
adding a bookmark depending on whether the secondary modifier is
pressed. Previously, the visible tooltip did not update when the
modifier changed while the popover was already open. This moves the
gutter hover intent into a shared state used by both the button and
tooltip, so the label, metadata, icon, color, click action, and
displayed keybinding all stay in sync.

Closes #58821

## How to Review

`crates/editor/src/editor.rs` adds a shared gutter hover intent type and
a custom tooltip view that reads the current modifier state while
rendering. Review that bookmark and breakpoint behavior map consistently
across the button icon/color, click action, tooltip label, metadata, and
keybinding.

`crates/editor/src/editor_tests.rs` adds a regression test covering the
tooltip intent selection with and without the secondary modifier.

Manual test after the fix below :

[Screencast from 2026-06-09
01-30-23.webm](https://github.com/user-attachments/assets/ef465eb9-e659-44da-93a6-a511c84e9401)

## Self-Review Checklist

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

Release Notes:

- Fixed the breakpoint/bookmark gutter popover not updating when
modifier keys change.

---------

Co-authored-by: Danilo Leal <daniloleal09@gmail.com>
2026-07-02 14:38:04 +00:00
Neel 969c6c719c editor: Fix panic when restoring empty selections on undo/redo (#59372)
Closes FR-81.

Also updates the error log, as the linked issue is closed.

Release Notes:

- Fixed panic when restoring empty selections on undo/redo
2026-07-02 13:07:42 +00:00