Follow-up to https://github.com/zed-industries/zed/pull/54100
Instead of relying on "line number" that could have overlapped depending
on the range we query, use hierarchical IDset: `block id -> lens #` to
ensure no clashes happen anymore.
Release Notes:
- N/A
Allows to reconfigure behavior, including the previous one, `top`
Closes https://github.com/zed-industries/zed/issues/52173
Release Notes:
- Reworked go to definition to open its target in the center of the
editor. Can be reconfigured with `go_to_definition_scroll_strategy`.
Hides and disables all mutating editor actions for readonly editors.
Certain actions (as cmd-backspace mentioned in the issue) could be
somewhat beneficial to have for navigation purposes, but we'd better
shape that story properly, let's build a "harness" and disable the
mutating ones first.
Closes https://github.com/zed-industries/zed/issues/47333
Release Notes:
- Fixed readonly editor having certain mutation actions enabled
The highlight queries only matched JSX member-expression tags when the
object was a plain identifier (`<A.B>`), so tags with more than one dot
like `<A.B.C>` lost their component-tag highlighting.
The fix explicitly captures every leaf `identifier` and
`property_identifier` at each nesting depth (up to 3 levels) in the
JavaScript and TSX highlight queries so each token gets its own
`@tag.component.jsx` capture that beats the generic `@property` rule.
A more concise approach, capturing the whole nested
`(member_expression)` node as a single `@tag.component.jsx` blob, does
not work because the generic `(property_identifier) @property` rule
targets a smaller, more specific node inside the blob, winning the
resolution for inner segments like `B` in `<A.B.C>`.
Closes#53305
Release Notes:
- Fixed highlighting for nested JSX member expression tags in JavaScript
and TSX files.
---------
Co-authored-by: dino <dinojoaocosta@gmail.com>
Painting primitives at non-integer pixel coordinates produces blurry
output. Pixel snapping converts layout coordinates into integer
device-pixel coordinates so painted edges land exactly on physical pixel
boundaries.
Non-integer coordinates can arise for several reasons, including:
- flex distribution, percentages, centering, and text measurement can
produce fractional element sizes and positions;
- at fractional scale factors (for example 125% or 150%), integer
logical-pixel values can map to non-integer device-pixel values.
We pixel-snap by rounding in device-pixel space, after multiplying by
`scale_factor`, so that snapping targets physical pixels. Bounds are
divided by `scale_factor` before being returned to GPUI.
Midpoints are rounded toward zero. This is a stylistic choice: a
1-logical-pixel line at 150% scale should render as 1 dp rather than 2
dp.
Pixel snapping is done in two phases:
1. Pre-layout metric snapping. Before Taffy computes layout, all
authored absolute lengths are rounded in `to_taffy`. This includes
borders, padding, gaps, and explicit sizes. Custom-measured leaf nodes
have their measured sizes rounded up to integer device-pixel lengths.
2. Post-layout edge snapping. After Taffy resolves the tree, layout
relationships such as flex shares, grid tracks, percentages, and
centering can produce new fractional edge positions. Boxes now have
edges in absolute coordinates, and snapping must decide where those
edges land on the device-pixel grid.
Ideally, post-layout snapping would satisfy:
- Edge closure. Two raw layout edges at the same absolute position
should snap to the same pixel column.
- Translation stability. A component's internal geometry should not
change when it moves to a new absolute position.
These goals are in tension because rounding is not associative. The
simple local schemes make different tradeoffs:
- Absolute edge rounding gives each window coordinate one answer, so
coincident edges always close globally. But a span's snapped length is
`round(far) - round(near)`, which may change by 1 dp as its absolute
origin moves.
- Parent-relative edge rounding rounds each child inside its parent's
coordinate space. This guarantees translation stability, but a shared
edge reached through different parents can accumulate different
rounding, causing non-closure between cousins.
- Length rounding rounds each width, height, and thickness independently
and then places boxes from those rounded lengths. Sizes stay stable
under translation, but neighboring boxes derive their shared boundary
from different sources, so closure is not guaranteed.
We apply absolute edge rounding for each element's outer box in
post-layout rounding to preserve closure. Border and padding widths are
not touched by post-layout rounding; they keep their pre-layout rounded
value so that they remain stable under translation.
This gives both closure and translation stability in the case that all
local metrics are integer device-pixel lengths. Pre-layout rounding
covers that in most cases. The exception is metrics resolved by layout
relationships, such as percentages. Outer box edges will still close
globally, and painted border widths are still snapped independently, but
the raw content-box origin can carry a 1 dp residual into descendants.
---
Fixes https://github.com/zed-industries/zed/issues/46360
Fixes https://github.com/zed-industries/zed/issues/44528
Fixes https://github.com/zed-industries/zed/issues/40282
Fixes https://github.com/zed-industries/zed/issues/42257
---
Release Notes:
- Fixed potentially blurry appearance of UI elements when using
fractional display scaling.
Closes#41580
This implements Helix's jump list, Zed already supports jumplists, so
all that is done is re-binding ctrl-s to to that instead. In another PR
we can extend this by adding space+j functionility to see all selections
in jumplist.
after this change:
Pressing Ctrl+S saves the current cursor position to the jumplist,
allowing the user to navigate back to this position using Ctrl+O
(backward) and Ctrl+I (forward), consistent with regular Helix's
behavior.
Release Notes:
- N/A *or* Added/Fixed/Improved ...
---------
Co-authored-by: Jakub Konka <kubkon@jakubkonka.com>
No, sadly, the title is not a typo. See
https://www.githubstatus.com/incidents/zsg1lk7w13cf for the context.
I'll read with joy and popcorn through that root cause analysis.
It makes literally zero sense what happened here, but for some completly
bonkers reason GitHub completely messed up the merge queue with
https://github.com/zed-industries/zed/pull/54632.
I have no idea how it happened. It makes literally zero sense. A PR
going into the merge queue should have the same LoC when getting out of
it. GitHub obviously does not check this. GitHub causes extra work with
a feature that is supposed to save time.
Thanks, I guess.
Release Notes:
- N/A
---------
Co-authored-by: Danilo Leal <daniloleal09@gmail.com>
- #54632 unintentionally reverted changes introduced in #54681, likely
due to a merge conflict resolution issue.
See the original PR for the changes.
Release Notes:
- N/A
Co-authored-by: Danilo Leal <danilo@zed.dev>
This PR brings back the button to filter remote branches when accessing
the title bar's branch picker with the mouse. It was unintentionally
removed when we introduced the new worktree picker.
Release Notes:
- N/A
- Don't render the tooltip while the menu is open to avoid collision
- Try to maintain the trigger element visible while the menu is open
- Tweak bookmarks icon and tooltip description copy
Release Notes:
- N/A
---------
Co-authored-by: Yara 🏳️⚧️ <git@yara.blue>
Co-authored-by: Joseph T. Lyons <JosephTLyons@gmail.com>
Reconciles `Open File` behaviour to the same action as using the
keybinds.
Closes#54502
Release Notes:
- Fixed a bug where the `Open File` button would not jump to the excerpt
containing the active cursor.
To hide the gutter_context_menu in collab notes (where it would be empty
anyway) we checked for the collaboration_hub. But that is unrelated to
collab notes it turns out :)
So now we check for the presence of a project which is always false for
collab notes.
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
Closes#54559
Release Notes:
- N/A Fixed context menu in the editor gutter not showing when there was
a break-point set but breakpoints are not shown in the buffer.
Search is highly generic, editor is the only implementation that has a
concept of a cursor. When the cursor moves eventually
`Editor::selections_did_change` runs which among a bunch of things
triggers the `SearchEvent::ActiveMatchChanged`. This was handled by the
`BufferSearchBar` by moving the currently highlighted item.
When going to the next search result (from the cursor position) we call
`BufferSearchBar::match_index_for_direction`. It relied on the
current_index being updated during the handling of `ActiveMatchChanged`
which we removed. It now instead figures out the next/prev search result
from the users cursor in the buffer directly.
The `SearchEvent::ActiveMatchChanged` was being used for different
responsibilities in different places in the codebase where it was
emmited, namely:
* On the `editor::Editor::selections_did_change` it was being emmited in
case a single selection (single cursor) existed, and this was the
thing reponsible for indirectly updating the active match as soon as
the cursor moved out of match.
* On the `terminal` side, it's being emitted when the user clicks on the
terminal, to "simulate" what the cursor position would be and update
the active match to the next closes match compared to the click
position.
* On the `markdown_preview` side it was being emmited whenever the
active match was updated but, from testing, it does actually seem to
not drive anything and is unnecessary?
Given that we no longer want to update the active match in the buffer
everytime the user moves the cursor, we removed the event emission from
`editor::Editor::selections_did_change` as well as removing the one from
`markdown_preview`, as it seems it doesn't have any noticeable impact.
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#44367
Release Notes:
- Fixed search highlighting changing anytime the cursor moves.
---------
Co-authored-by: Yara <git@yara.blue>
Fixes#49466
It looks like this wasn't actually a bug in the PHP outline query, but a
general sticky scroll bug. In PHP, the attribute ends up inside the
`function_declaration` as a child node, so sticky headers were
previously taking their start from `item.range.start` and getting stuck
on the `#[Deprecated]` line instead of `function foo()`. Switching to
`source_range_for_text.start` fixes exactly that, and also covers other
languages that put decorators or attributes before the declaration. I
added the test in TypeScript because it has the same tree shape and
covers the same class of bug as #49466
---
Before:
<img width="967" height="772" alt="Screenshot from 2026-04-07 08-46-10"
src="https://github.com/user-attachments/assets/a6b2aa2b-03f7-4abf-a4c4-c87d41df83ae"
/>
After:
<img width="1245" height="993" alt="Screenshot from 2026-04-07 08-23-32"
src="https://github.com/user-attachments/assets/27ef2487-d7fd-4a73-93e5-97fc719f9245"
/>
<img width="1245" height="993" alt="Screenshot from 2026-04-07 08-23-40"
src="https://github.com/user-attachments/assets/1b1daf80-544d-4128-bc92-b7d44b8d6564"
/>
<img width="963" height="636" alt="Screenshot from 2026-04-07 08-23-53"
src="https://github.com/user-attachments/assets/bb244ce9-797e-4a5f-b48f-eb0e4b982f7d"
/>
---
Tests:
Nextest run ID f0de6791-1a3c-406b-9589-54df870b832b with nextest
profile: default
Starting 3 tests across 1 binary (655 tests skipped)
PASS [ 0.986s] (1/3) editor editor_tests::test_sticky_scroll
PASS [ 0.436s] (2/3) editor
editor_tests::test_sticky_scroll_with_decoration_prefix_in_item
PASS [ 0.822s] (3/3) editor
editor_tests::test_sticky_scroll_with_expanded_deleted_diff_hunks
────────────
Summary [ 2.298s] 3 tests run: 3 passed, 655 skipped
Release Notes:
- Fixed sticky scroll headers showing attribute/decorator lines instead
of the declaration line in PHP and other languages where annotations are
child nodes of the declaration.
Co-authored-by: dino <dinojoaocosta@gmail.com>
## Summary
- Enable VSCode-like side-by-side file comparison in FileDiffView using
SplittableEditor
- Leverages existing SplittableEditor infrastructure that ProjectDiff
already uses
- Controlled by the user's `diff_view_style` setting (split/unified)
## Changes
- `crates/git_ui/src/file_diff_view.rs`: Refactored to use
SplittableEditor instead of plain Editor (+66/-30 lines)
## Test plan
- [ ] Open a file with git changes and verify the diff view renders
correctly
- [ ] Toggle between split and unified diff view styles via settings
- [ ] Verify side-by-side comparison shows old/new content correctly
Release Notes:
- Enabled side by side diffs in the file diff view
Co-authored-by: Lukas Wirth <me@lukaswirth.dev>
Basically just applied the suggested fix as described in #53606 , I also
experimented with a hackier soln. that used the same logic as the code
this is replacing, but it seemed solidly worse than this version.
The original issue extremely clear with what is going on / what needed
to be fixed.
heres a video:
https://github.com/user-attachments/assets/e7fc60f7-0a8c-403c-877f-93f58f370b00
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#53606
Release Notes:
- editor: Fixed incorrect inclusion of comments into folds
Previously, passing an empty range to `range_to_buffer_range` would
return no ranges, which would trigger a fallback case in the git diff
that caused the entire multibuffer to be invalidated every frame.
This PR fixes `range_to_buffer_range`, so that it returns a sensible
range if the input range is empty, preventing the fallback behaviour and
edit expansion.
Self-Review Checklist:
- [ ] I've reviewed my own diff for quality, security, and reliability
- [ ] Unsafe blocks (if any) have justifying comments
- [ ] 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
- [ ] Performance impact has been considered and is acceptable
Closes #ISSUE
Release Notes:
- N/A or Added/Fixed/Improved ...
---------
Co-authored-by: Cole Miller <cole@zed.dev>
Co-authored-by: Anthony Eid <hello@anthonyeid.me>
Fixes an autoscroll bug that sometimes obscures the current row behind a
sticky header.
The bug was caused by `Editor::autoscroll_vertically` using the
`sticky_header_line_count` value that was cached during the previous
render, which isn't necessarily the number of sticky headers that the
scroll target needs, e.g.
- when jumping to a definition
- when pressing the up arrow key when the selection is in the topmost
visible row with `"vertical_scroll_margin": 0`
This fixes that by not caching `sticky_header_line_count` and instead
querying Tree-sitter on the fly to get the number of sticky headers that
the scroll target needs. Performance-wise this seem okay, I measured it
to take less than 200µs on my machine using a very large Rust file (and
there are still some possible ways to optimize this if necessary). In
particular, the pathological huge single-line file case as discussed in
#48450 shouldn't be an issue here because unlike the main sticky header
Tree-sitter query, here we query the outline items that contain a
particular point rather than those that intersect an entire row.
The `ScrollCursorTop` handler is also simplified to use the same shared
function for counting the number of sticky headers, since that action
doesn't rely on autoscroll.
Before:
https://github.com/user-attachments/assets/efb12776-82d9-4b94-baa5-347ec769fb98
After:
https://github.com/user-attachments/assets/236deb9f-fe06-43bd-b167-7bd3ab719e4c
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#50803
Release Notes:
- Fixed sticky headers sometimes obscuring the current row.
---------
Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
## Summary
Fix completion ordering when two items are otherwise tied and only
differ by letter case.
In cases like `abc` vs `ABC`, if the user types `a`, Zed should prefer
`abc`. If the user types `A`, Zed should prefer `ABC`. This matches the
expectation described in #37081 and #27993, where `subscription` should
rank above `Subscription` for query `s`.
## What changed
In `CompletionsMenu::sort_string_matches`, I added a tie-breaker that
prefers completions with more exact case-sensitive matches at the
fuzzy-match positions.
This only applies after the existing higher-priority sort keys, so it
does not replace fuzzy score, match positions, snippet ordering, or LSP
`sortText`. It only resolves ambiguous ties more intuitively.
## Tests
Added regression coverage in `code_completion_tests` for abstract
case-only examples:
- `a` prefers `abc` over `ABC`
- `A` prefers `ABC` over `abc`
- `ab` prefers `abc` over `ABC`
- `AB` prefers `ABC` over `abc`
- mixed-case multi-letter queries like `Ab` and `aB`
## Verification
Ran:
```bash
cargo test -p editor code_completion_tests
```
PS: all code and description is generated by Codex
Release Notes:
- Fixed completions not tie braking by case
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 a panic when using the split diff view.
Update how auto indentation is handled by `Editor::newline`, in the case
where auto-indentation is not `AutoIndentationMode::None`, so as to
extend the range of the edits being applied to the beginning of the
line, in case the line only contains the indentation whitespace or
there's only whitespace indentation before the cursor position
This ensures that newlines are not left with whitespace.
Closes#34316
Release Notes:
- Fixed auto indent leaving trailing whitespace on blank indented lines
when creating new lines.
---------
Co-authored-by: dino <dinojoaocosta@gmail.com>
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#52559
Release Notes:
- Fixed an issue where holding the modifiers used in
`editor::AcceptEditPrediction` would cause the code action menu to
dissapear
Update all direct calls to `Editor::inline_blame_popover::take` to now
be calls to `Editor::hide_blame_popover` as this ensures that the
popover is also not shown in case its task still hasn't finished.
This fixes a bug where the inline git blame popover could be shown even
after the user had opened a modal.
Release Notes:
- Fixed the inline Git blame popover sometimes appearing after opening a
modal.
---------
Co-authored-by: dino <dinojoaocosta@gmail.com>
Super small update changing two instances where
`DiagnosticSeverity::HINT` was set to use the color for "info".
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
Closes#45637
Release Notes:
- Fixed various instances of hint level diagnostics using the color
designated for info
Hover popovers aren't immediately dismissed when the hover ends, but
this delay mechanism is currently causing popovers to sometimes still
briefly appear when the hover lasted too short to have triggered it.
Fixed by immediately cancelling the popover task when the hover ends
before the popover is displayed.
Most easily reproduced when setting the hover popover delay to a value
lower than the default 300ms (but it still happens sometimes with the
default value), because the popover hide delay is also 300ms. Here's it
with `"hover_popover_delay": 200`:
https://github.com/user-attachments/assets/6415d112-d8e0-4a87-9a79-a7ab559f20f2
After the fix:
https://github.com/user-attachments/assets/34782389-de4c-4a25-bd6e-4858b55028de
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
Release Notes:
- Fixed hover popovers sometimes briefly appearing after the hover
already ended.
---------
Co-authored-by: Lukas Wirth <lukas@zed.dev>
We had an internal report of soft wrap not working in git panel's commit
editor. Given the following settings:
```json
{
"languages": {
"Git Commit": {
"preferred_line_length": 80,
"soft_wrap": "preferred_line_length",
},
},
}
```
We would not soft-wrap in narrow viewports. As it turned out, the
problem was that we were always prefering a `preferred_line_length` as
our soft wrap boundary over the actual width of the editor.
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 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
Closes #ISSUE
Release Notes:
- Fixed git commits editor not respecting soft wrap boundaries.
- settings: Removed `"soft_wrap": "preferred_line_length"` in favour of
`"soft_wrap": "bounded"`. Soft wrap now always respects editor width
when it's enabled.
Adds basic bookmark functionality to the editor, allowing users to mark
lines and later navigate between them. This is an MVP and will later be
expanded with a picker, vim marks integration and syntax tree based
bookmark positions. In this MVP bookmarks shift under external edits.
# UI
## Adding/Removing bookmarks
To add a bookmark:
- run the toggle bookmark action
- hold secondary and click in the gutter
- open the context menu by right clicking in the gutter and select add
bookmark To remove a bookmark:
- run the toggle bookmark action
- click on the bookmarks icon in the gutter
- open the context menu by right clicking in the gutter and select
remove bookmark
remove all bookmarks with `workspace: clear bookmarks`
# Implementation
This mirrors the implementation of breakpoints. The rendering of the
gutter was refactored to make place for bookmark icons and buttons:
- Code was extracted to a `Gutter` struct
- Runnables, breakpoints and bookmarks are now collected ahead of
layouting. Just before layouting we remove the items that collide and do
not have priority.
- The `phantom_breakpoint` is replaced by a `gutter_hover_button`
## In depth phantom breakpoint discussion:
This was phantom_breakpoint. It worked as follows:
- A fake breakpoint was added to the list of breakpoints.
- While rendering the breakpoints it a breakpoint turned out to be fake
it would get a different description and look.
- The breakpoint list was edited run_indicators ("play buttons")
rendering to removes the fake breakpoint if it collided.
This would not scale to more functionality. Now we only render
breakpoints, bookmarks and run indicators. Then we render a button if
there is not breakpoint, bookmark or run indicator already present. We
can do so since the rendering of such "gutter indicators" has been
refactored into two phases:
- collect the items.
- render them if no higher priority item collides.
This is far easier and more readable which enabled me to easily take the
phantom_breakpoint system and use it for placing bookmarks as well :)
Note: this was previously merged but it needed a better squashed commit
message. For the actual PR see: 51404. This reverts commit
1c3846e76f.
Release Notes:
- Added Bookmarks
Co-authored-by: Austin Cummings <me@austincummings.com>
Closes#4526
Adds basic bookmark functionality to the editor, allowing users to mark
lines and later navigate between them.
### What's new
**Toggling bookmarks**
Users can toggle a bookmark on the current line(s) via the `editor:
toggle bookmark` action. A bookmark icon appears in the gutter for each
bookmarked line.
**Navigation**
Two new actions, `editor: go to next bookmark` and `editor: go to
previous bookmark`, navigate between bookmarks in the current buffer,
wrapping around at the ends of the buffer.
**Viewing all bookmarks**
`editor: view bookmarks` opens all bookmarks across the project in a
multibuffer, similar to how references and diagnostics are surfaced.
**Clearing bookmarks**
`workspace: clear bookmarks` removes all bookmarks in the current
project.
**Persistence**
Bookmarks are persisted to the workspace database and restored when the
workspace is reopened. They are stored as `(path, row)` pairs and
resolved back to text anchors. Out of range or unresolvable bookmarks
are skipped with a logged warning.
**Gutter rendering**
Bookmark icons are rendered in the gutter using the existing gutter
button layout system, consistent with breakpoints. They are suppressed
on lines that already show a breakpoint or phantom breakpoint indicator.
A new `gutter.bookmarks` setting (defaulting to `true`) controls their
visibility.
### What's left
- [x] Lazily load buffers that have bookmarks
- [x] Clean up test boilerplate
- [ ] Assign default keybindings
- [ ] Compare line of saved bookmarks with current buffer (gray out the
"stale" bookmarks)
### What's next (and nice to haves)
- [ ] Resilience against external edits
- [ ] Save column position with the bookmark
- [ ] Bookmarks attached to syntactic structures?
- [ ] Labeled bookmarks?
---
Release Notes:
- Added bookmarks: toggle bookmarks on lines with `editor: toggle
bookmark`, navigate with `editor: go to next bookmark` / `editor: go to
previous bookmark`, view all bookmarks with `editor: view bookmarks`,
and clear with `workspace: clear bookmarks`. Bookmarks are shown in the
gutter and persisted across sessions.
---------
Co-authored-by: Yara <git@yara.blue>
Fixes this single-frame glitch that sometimes occurs when the git blame
popover is rendered before the markdown has been parsed.
https://github.com/user-attachments/assets/d5a322c3-e46f-4597-a10f-a676da57daa7
## 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)
- [ ] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Release Notes:
- Fixed a visual glitch where the git blame popover could briefly appear
empty while its markdown content was being parsed
Changed the offset-to-display-point conversion in `find_boundary_point`
and `find_boundary_trail` to use `Bias::Right`, so positions inside
folds map to the fold end, letting the cursor skip past folded ranges.
Closes#53978.
Release Notes:
- Fixed Ctrl+Right and related word movement shortcuts failing to skip
over folded ranges and `@mention` chips
## What Changed
- compute range-format support from formatter configuration and
language-server capabilities
- show `Format Selections` only when at least one selected buffer has a
range-capable formatter
- keep Prettier-supported range formatting available without depending
on LSP support
- hide the action for formatter modes that cannot honor selections, such
as external-command and code-action formatters
- keep the action handler safe by rechecking support and returning early
when range formatting is unavailable
- restrict capability checks to the servers actually registered for the
current buffer
- add regression coverage for supported, unsupported, and mixed-server
cases
- document when `Format Selections` is available in both action docs and
user docs
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#25796
Release Notes:
- Improved `Format Selections` so it is only shown when the active
formatter supports range formatting.
Testing I did:
Here are the formatters I used:
<img width="829" height="434" alt="Screenshot_20260405_102047"
src="https://github.com/user-attachments/assets/cae4a238-277e-4188-873f-189e9f098699"
/>
Note: I've chosen three formatters:
1. Prettier, which supports range formatting
2. clangd (LSP) which also supports range formatting
3. gopls which do not support range formatting
[Screencast_20260405_102431.webm](https://github.com/user-attachments/assets/69ce3f95-0b73-46a0-853d-3b5be6329dde)
---------
Signed-off-by: Pratik Karki <pratik@prertik.com>
Co-authored-by: Kirill Bulatov <kirill@zed.dev>
## Context
When a file is renamed via the project panel while open in an editor,
Zed would restore the old (no longer existing) path on reload .
On rename, `language::Buffer` emits `BufferEvent::FileHandleChanged`,
which propagates to `multi_buffer::Event::FileHandleChanged` →
`EditorEvent::TitleChanged`. However, `should_serialize()` only matched
`Saved | DirtyChanged | BufferEdited`, so no re-serialization was
triggered and the `editors` DB table retained the stale `abs_path`.
The fix adds a dedicated `EditorEvent::FileHandleChanged` variant, emits
it alongside `TitleChanged` when the buffer's file handle changes, and
adds it to `should_serialize()`. Since `Editor::serialize()` already
reads the current path from the buffer at call time, this naturally
writes the new path to the DB.
Closes#51629
## How to Review
Three files edited:
- `editor.rs`: splits `FileHandleChanged` into its own arm and emits the
new event variant
- `items.rs`: adds `FileHandleChanged` to `should_serialize`
- `items.rs` (test): `test_file_handle_changed_on_rename` does a full
rename via `Project::rename_entry` and asserts the event fires and the
buffer path updates
## 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](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:
- Fixed renamed files being reopened with their old path after a restart
**Important remark :**
This pull request is a follow-up on the review of @SomeoneToIgnore on
this pull request, https://github.com/zed-industries/zed/pull/51717,
which was inadvertently closed because I mistakenly deleted my previous
fork of the zed repo, sorry for any inconvenience caused by this
Manual test video below :
[Screencast from 2026-03-16
23-28-46.webm](https://github.com/user-attachments/assets/ff2e3259-ae26-4655-83b8-f693e84306d2)