2e2fb0a21811ce2dbaca5bb738b0be8f94de051e
5168
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
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
|
||
|
|
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> |
||
|
|
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. |
||
|
|
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. |
||
|
|
5c215b3613 |
Revert "editor: Add language detection for untitled buffers (#61201)" (#61351)
This reverts commit
|
||
|
|
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> |
||
|
|
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. |
||
|
|
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. |
||
|
|
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 ... |
||
|
|
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. |
||
|
|
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.
|
||
|
|
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. |
||
|
|
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. |
||
|
|
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> |
||
|
|
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> |
||
|
|
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. |
||
|
|
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> |
||
|
|
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> |
||
|
|
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. |
||
|
|
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 |
||
|
|
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. |
||
|
|
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 ... |
||
|
|
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 |
||
|
|
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 |
||
|
|
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> |
||
|
|
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>
|
||
|
|
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. |
||
|
|
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> |
||
|
|
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> |
||
|
|
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 |
||
|
|
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> |
||
|
|
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> |
||
|
|
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 |
||
|
|
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 ... |
||
|
|
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 ... |
||
|
|
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
|
||
|
|
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> |
||
|
|
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> |
||
|
|
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 |
||
|
|
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> |
||
|
|
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 ... |
||
|
|
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> |
||
|
|
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. |
||
|
|
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> |
||
|
|
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> |
||
|
|
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. |
||
|
|
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> |
||
|
|
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> |
||
|
|
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> |
||
|
|
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 |