# Objective
Opening a file laods it twice. `decode_file_text` builds the whole file
as a `String`, and that `String` stays alive alongside the finished rope
while `text::Buffer::new` copies it in. The `Vec` behind it grows by
doubling, so it also commits up to nearly the file's size again in
capacity it never uses.
Partially addresses #27283.
## Solution
Add `decode_file_text_to_rope`, which streams the file in 1 MB blocks
straight into a `Rope`, validating UTF-8 and normalizing line endings as
it goes. The file is never fully held as a `String`.
`LoadedFile::text` becomes a `Rope` carrying the `LineEnding` detected
before normalizing, so `buffer_store` calls `Buffer::new_normalized`.
## Testing
On a 729 MB SQL dump, peak memory fell 25% and CPU fell around 28%.
tested on 5950x, win11.
Release Notes:
- Improved memory use when opening large files, reducing peak memory
during load by roughly the size of the file itself.
Bumps the treesitter version to include
https://github.com/tree-sitter/tree-sitter/pull/5851
Also makes some changes to `cx.spawn_dedicated` to make it work on web:
- remove the blocking `recv` on the main thread
- adds a new variant `TaskState::Rendezvous` to allow this code to
synchronously return a task
`TaskState::Rendezvous` is needed because of how
`spawn_dedicated_thread` works:
- the caller provides a callback that produces a non-`Send` `Future` on
the dedicated thread
- the callback is sent to the dedicated thread, executed, and the
resulting `Task` is sent back to the main thread
- this all happens synchronously, so that `spawn_dedicated_thread`
returns a synchronous `Task`
However, the blocking `recv` on the main thread traps on the main worker
in the browser.
This PR replaces that with a call to `recv_async`, but this requires a
new `Rendezvous` variant on `TaskState` which represents "a task that it
still waiting to receive the underlying handle from the dedicated
thread".
It also enables the `flume/spin` feature on the web, which is needed to
avoid a synchronous lock acquisition in `send` (it's replaced with a
spinlock). Note that `send_async` wouldn't work here because it acquires
the same lock, and it's unnecessary because `send` only blocks when the
channel is full, but it's an unbounded channel.
---
Release Notes:
- N/A or Added/Fixed/Improved ...
# Objective
Fixes#60192
Closes https://github.com/zed-industries/zed/issues/62308
`editor: align selection` lines cursors up by their buffer column, and
that column counts bytes. If a multi-byte character sits before the
cursor, the byte column is larger than the position the cursor is
actually drawn at, so the row gets padded with the wrong number of
spaces.
The issue reports it with `←` (3 bytes) and `π` (2 bytes):
```
a ← 1 # one
bc ← π # two
```
Put a cursor on each `#`, run the action, and the result is still
misaligned:
```
a ← 1 # one
bc ← π # two
```
This is not the columnar selection bug fixed in #57097. That one was
`select_columns` in `selection.rs`, where the output is a selection
range. This one is `align_selections` in `editor.rs`, where the output
is inserted spaces, so the same byte-column assumption was left behind
in a second place, and fixing it here needs a rounding step that the
first fix did not.
## Solution
Measure each cursor by its x offset in the laid-out display row
(`DisplaySnapshot::x_for_display_point`), take the target for a column
as the furthest x across the rows, then turn the difference into whole
spaces by dividing by the advance width of `' '`. The offset that
carries into later columns becomes an x offset instead of a column
count.
The display map has already expanded tabs by the time the row is laid
out, so a leading tab now counts as its expanded width instead of as a
single byte.
Two things I would look at first in review:
- The division rounds instead of truncating. The x offsets are built by
repeated float addition, so a gap that should be exactly three spaces
can arrive as 2.9999998, and truncating inserts two.
- The function returns early if the space advance is missing or zero.
Dividing by zero gives `inf`, which saturates to a huge `u32` and then
tries to allocate that many spaces.
I did not add any public items and did not touch `selection.rs`.
## Testing
`cargo test -p editor align` on Windows: 6 passed, 0 failed. That is the
new test plus the two existing `align_selections` tests, which I did not
change and which still pass.
`test_align_selections_with_multibyte_chars` covers the repro from the
issue, a second column whose offset has to carry past a multi-byte
character in the first, a leading tab, a non-BMP character, and a case
where multi-byte characters sit after the cursors and nothing should
move.
I also checked that the test catches the bug rather than just passing:
reverting the change in `editor.rs` and keeping the test makes it fail
on the repro, inserting four spaces where three are right. Putting the
change back makes it pass. The two older align tests pass either way,
since they are pure ASCII.
What I have not covered:
- Wide CJK characters, combining marks, and ZWJ clusters. These should
be right by construction, since the code measures advances rather than
counting characters, but I have no tests for them. The headless text
system behind `gpui::test` gives every BMP character the same advance,
so a test there would assert the test double's behavior rather than the
real renderer's.
- Proportional fonts. Aligning with inserted spaces cannot be exact when
glyph widths vary. The code rounds to the nearest whole space.
- Soft-wrapped rows. I measure x from the start of the wrapped row but
still group cursors by buffer row, so two cursors on one buffer row that
sit either side of a wrap boundary get measured from different origins,
and the carried offset crosses that boundary as if they shared one. The
old byte-column code did not have that particular failure. I left it
alone because fixing it is a different change, but I would rather flag
it than have you find it.
- I work on Windows and have no macOS machine. The arithmetic is
platform independent, so I do not expect a difference, but I have not
checked.
To try it: paste the two lines from the issue, put a cursor on each `#`
with `editor: select next`, then run `editor: align selection`. The two
`#` should line up.
## 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:
- Fixed `editor: align selections` misaligning rows and Vim `ctrl-d` /
`ctrl-u` / `ctrl-f` leaving the cursor behind on lines with multi-byte
characters or tabs.
---------
Co-authored-by: Kirill Bulatov <kirill@zed.dev>
# Objective
Make `G` keybinding in Helix mode work like in Helix and not like in
Vim.
Fixes https://github.com/zed-industries/zed/issues/61580
## Solution
Helix has two ways to jump to a line by line number.
One is the `goto_file_start` command (bound to `gg`) that optionally
takes a count to go to that line instead of the start of the file. Zed
already supports it as `vim::StartOfDocument`.
The other is the dedicated `goto_line` command (bound to `G`) that only
does that and nothing else. Zed did not have it.
What's worse, the default `"shift-g": "vim::EndOfDocument"` binding
leaked from Vim keymap into Helix keymap, which previously made
`<count>G` accidentally work in Helix mode for the wrong reason, until
https://github.com/zed-industries/zed/pull/59449 fixed the behavior of
`vim::StartOfDocument` and `vim::EndOfDocument` actions to match Helix
exactly. This broke `<count>G` and exposed that `G` was bound to the
wrong action in Helix mode, and the correct one didn't exist.
This PR fixes that in the following way:
- adds new`vim::HelixGotoLine` action
- binds it to `shift-g` in `helix_normal` and `helix_select` modes in
the default Vim keymap
## Testing
- Unit tests
- Manual testing
## 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 the behavior of `G` binding in Helix mode and added new
`vim::HelixGotoLine` action
Signed-off-by: Oleksii Orlenko <alex@aqrln.net>
## Why
`textDocument/onTypeFormatting` edits that insert or replace text at an
empty cursor use its right bias and move it past the new text. In paired
tags, pressing Enter can therefore leave the cursor on the closing tag
instead of between the tags.
## What
- Capture a left-biased pin for each empty cursor before requesting
on-type formatting.
- Skip cursor tracking unless a matching language server advertises the
trigger.
- Restore only unchanged empty cursors whose displacement is fully
covered by formatting transaction ranges, so intervening user edits are
preserved.
- Reset vertical movement state when restoring a cursor.
## Testing
- `cargo test -p editor test_on_type_formatting` (5 passed)
- `./script/clippy -p editor`
## References
- Fixes https://github.com/zed-industries/zed/issues/61574
Release Notes:
- Fixed the cursor being moved past text inserted or replaced at its
position during on-type formatting.
---------
Co-authored-by: Kirill Bulatov <kirill@zed.dev>
# Objective
Closes#41744
When a multi-key binding switches from Insert mode to Helix normal mode,
subsequent editing actions can place the cursor incorrectly.
While a printable multi-key binding is pending, Zed temporarily inserts
the pending keys into the buffer. Once the binding is matched, Zed
dispatches the associated action and then deletes the pending text.
Because the buffer uses a CRDT, the deleted text remains as tombstoned
fragments. The cursor can still resolve to the correct visible offset
while its selection anchor remains associated with one of those
fragments, affecting the ordering of subsequent edits.
Among the explicit Vim mode-switch actions, `SwitchToHelixNormalMode` is
the only one that preserves the existing selections:
ce6f3af5f7/crates/vim/src/vim.rs (L713-L719)
As a result, the tombstone-associated anchor is carried into Helix
normal mode, where later actions such as `o` can place the cursor on the
wrong side of the inserted newline.
The affected path is narrow: a multi-key binding must invoke
`SwitchToHelixNormalMode` from Insert mode. This creates pending text
and then preserves the resulting selection anchors when entering Helix
normal mode.
There are two possible layers at which to address this. At the Editor
layer, selections could be refreshed whenever pending text is removed so
that they no longer reference deleted fragments. At the Vim layer, the
Helix mode transition can explicitly guard against preserving those
anchors.
PR #50918 attempted the broader Editor-layer solution by refreshing
selections after resolving a multi-key binding. However, as discussed in
this review comment:
https://github.com/zed-industries/zed/pull/50918#issuecomment-4411319469,
the more appropriate scope for this reported issue is the Vim
mode-switching layer.
## Solution
Based on PR #50918 and its review feedback, this PR limits the fix to
`SwitchToHelixNormalMode`.
When that action is triggered by pending Insert-mode keystrokes, Vim
refreshes the preserved selection anchors after the pending text is
removed. This keeps the fix scoped to the affected Helix transition
without changing other multi-key bindings.
## Testing
Added a GPUI regression test.
## 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 incorrect cursor placement after using a multi-key binding to
leave insert mode in Vim or Helix mode.
---------
Co-authored-by: dino <dinojoaocosta@gmail.com>
Fixes InsertLineAbove (Shift + O) auto-indent handling by deciding
whether to trim the first character or the last character based on
direction. Previously, inserting a line above would auto format the line
the cursor was originally on and not the new line (instead of the
correct behavior which is to do the opposite).
No tests because I couldn't find any Vim-specific auto-indent tests and
this only affects Vim mode. If I'm missing something there LMK and I'll
take a closer look.
Closes#52588.
Release Notes:
- Vim: Fixed auto-indentation for insert above action.
---------
Co-authored-by: dino <dinojoaocosta@gmail.com>
# Objective
Fixes#58492.
With Vim mode enabled and an editor focused in normal mode, Escape does
not close the release notes notification shown after an update. Vim
consumes Escape before the workspace can handle `menu::Cancel`.
## Solution
Add Windows-specific Escape bindings for `menu::Cancel` in Vim and Helix
normal modes. Place them after the existing Escape bindings so GPUI
tries `menu::Cancel` first.
This is limited to Windows because macOS and Linux already provide
non-conflicting `Ctrl-C` and `Ctrl-Escape` alternatives, respectively.
## Testing
Added regression coverage for dismissing workspace notifications with
Escape in Vim normal mode.
I verified the test passes and the visible notification is dismissed
locally.
## Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content adheres to Zed's UI standards
([UX/UI](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
and
[icon](https://github.com/zed-industries/zed/blob/main/crates/icons/README.md)
guidelines)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
## Showcase
https://github.com/user-attachments/assets/3895385f-7be1-4c62-8d7c-05a5b580d855
---
Release Notes:
- Fixed release notes notifications not closing with `escape` when Vim
or Helix mode is enabled, on Windows.
## Purpose
While developing a theme for Zed I remarked that the schema available
doesn't mark colors in a way that Zed recognize to display the color
annotations:
```json
{
"$schema": "https://zed.dev/schema/themes/v0.2.0.json"
}
```
<img width="119" height="190" alt="Screenshot 2026-02-25 at 23 15 10"
src="https://github.com/user-attachments/assets/3f1bb703-cb26-4630-9598-3a7cb8873c20"
/>
But Zed has support for it when colors are marked with `"format":
"color"` in the schema:
<img width="127" height="186" alt="Screenshot 2026-02-25 at 23 14 58"
src="https://github.com/user-attachments/assets/1a9387a4-613a-4cf8-a3af-f6ac201bdf54"
/>
So I searched if the schema file was Open Source somewhere, discovered
it was generated from the codebase and attempted the change.
## Implementation
This is essentially done using a `ThemeColor` wrapper for the color
strings that implements `JsonSchema` with a dedicated regex for
validation and the color format specified. This ends up with a new
`$defs` of `Color` being specified and used:
```json
{
"$defs": {
"Color": {
"type": "string",
"format": "color",
"pattern": "^#([0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$"
}
}
}
```
## Other
- There is a small change I made for testing to the schema_generator
that adds an `--output` / `-o` flag. When provided it writes the
generated schema JSON to the specified file path instead of printing to
stdout. This was done to made testing easier but I can remove it or
split it to a separate PR (It's already a separate commit)
- For this PR to do anything a new schema version will need to be
published at something like `https://zed.dev/schema/themes/v0.3.0.json`
and documentation needs to be updated to point to it.
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 (Manual testing, couldn't find any existing good place to test
it)
- [x] Done a self-review taking into account security and performance
aspects
- [x] Aligned any UI changes with the [UI
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
Release Notes:
- N/A
---------
Co-authored-by: MrSubidubi <finn@zed.dev>
# Objective
Fixes#59129.
`vim::HelixJumpToWord` currently treats its two-character target labels
as text input. When an IME is active, the printable label keys can
therefore enter the IME composition window instead of completing the
jump.
## Solution
- Treat an active Helix jump as command input rather than character
input, preventing the platform input handler from preferring the IME for
its label keys.
- After normal keybinding resolution, handle action-less, unmodified
label keydowns directly from the keystroke's ASCII-equivalent key. This
preserves label matching on non-ASCII keyboard layouts while leaving
Escape, custom bindings, and Ctrl/Alt/Cmd/Function shortcuts untouched.
- Stop propagation after consuming a label key so the platform does not
subsequently forward it to the IME.
- Keep the existing committed-text handling as a fallback for other
input paths.
This is complementary to #61270: that PR handles pending GPUI keybinding
chords before IME input, while this change handles Helix jump labels
after the initiating action has resolved. The changes are also
file-disjoint.
## Testing
- Added a regression test using the issue's `s` → `vim::HelixJumpToWord`
binding. The test verifies that:
- no GPUI keybinding chord is pending;
- Helix jump does not accept text input or prefer the IME;
- both raw label keydown events are consumed; and
- the expected jump completes.
- Manually tested on macOS with both ABC and Japanese Romaji input
sources.
## 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 Helix jump-to-word label input being intercepted by IMEs.
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#53517
Release Notes:
- Added Helix trim whitespace from selections action on `_`.
---------
Co-authored-by: Tom Houlé <tom@tomhoule.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#54231
Related to the Opire Helix keymap bounty on #4642.
/claim #4642
Opire payout: @jamilahmadzai
Release Notes:
- Fixed Helix mode append so pressing Escape without inserting text
restores the original cursor or selection instead of leaving it one
character ahead.
---------
Co-authored-by: Tom Houlé <tom@tomhoule.com>
# Objective
Remove `.unwrap()` calls in iterator/`Option` chains that could panic at
runtime.
## Solution
Use `and_then`/`filter_map` with `.ok()` for fallible downcasts
(`entry_view_state.rs`) and keystroke parsing (`vim/command.rs`); use a
descriptive `expect` in `suggest_autoindents` where the invariant is
intentional (`buffer.rs`).
## Testing
- `cargo test -p language buffer` (69 passed)
- `cargo test -p vim command` (26 passed)
- `cargo test -p agent_ui entry_view` (3 passed)
## Self-Review Checklist:
- [x] I have reviewed my own diff for quality, security, and reliability
- [ ] Unsafe blocks (if any) have justifying comments
- [ ] The content adheres to Zed's UI standards
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Release Notes:
- N/A
Previously, the `[` and `]` marks always pointed to the yank source
location. After a paste operation, they now correctly point to the start
and end of the pasted text in the destination buffer.
This enables workflows like `v]` to select just-pasted text, and fixes
the `gp` keymap pattern shown in the issue.
Closes https://github.com/zed-industries/zed/issues/56404
Release Notes:
- vim: Made `[` and `]` marks point to the start and end of pasted text
after a paste operation.
---------
Signed-off-by: Xiaobo Liu <cppcoffee@gmail.com>
Co-authored-by: Tom Houlé <tom@tomhoule.com>
# 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:
c9e8e611db/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):
c9e8e611db/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):
c9e8e611db/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:
c9e8e611db/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.
# Objective
- Fixes#53650
- Possibly also fixes#57956 (needs confirmation)
## Solution
- Replace the direct `DisplayPoint::new(row, col)` construction with a
proper buffer-point-to-display-point
- This goes through the full inlay → fold → tab → wrap → block pipeline
and correctly accounts for any inlay hints on the target line.
## Testing
- Added a regression test for multi-cursors with inlay hints in helix
mode
## 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 `Shift+C cursor` position with inlay hints in helix mode
## Why / What
Fixes#58702.
In Helix mode the block cursor is a one-character selection that can
rest on the
trailing newline at the end of a line. When you select to the end of a
line
(excluding the newline) and press `d`, Helix leaves the cursor on the
newline.
Zed instead clamped the cursor onto the character immediately to the
left of the
deleted selection.
The shared `visual_delete` always re-clipped the post-deletion cursor at
line
ends (`set_clip_at_line_ends(true)`), which is correct for Vim normal
mode but
contradicts Helix mode, where `Vim::clip_at_line_ends()` is `false`.
This also
made Helix inconsistent with itself: deleting a whole line left the
cursor on the
newline, but deleting to the end of a non-empty line clamped it onto the
previous
character. The fix honors the active mode's clip policy, so Helix keeps
the
cursor on the newline.
## Testing
- Added `test_delete_to_end_of_line_keeps_cursor_on_newline` reproducing
#58702.
- Corrected `test_helix_select_end_of_line`; its mid-line assertion had
captured
the pre-fix (clamped) cursor position. Its whole-line assertion already
expected the cursor on the newline, so the test is now internally
consistent.
- `cargo test -p vim`: 540 passed, 0 failed.
- Vim visual-mode delete is unchanged (`is_helix()` is false for Vim
modes).
Release Notes:
- Fixed Helix mode placing the cursor on the wrong character after
deleting a selection that ends at the end of a line.
---------
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#54160
Summary:
In Helix mode, rename could fail when the cursor was visually positioned
on the last character of a symbol. The editor renders some Vim/Helix
selections with the visible cursor offset from the selection head, but
rename was still using the raw selection head as the LSP prepare-rename
position.
This updates rename to use the visible cursor position for point lookup
when cursor offset rendering is active. It also adds regression coverage
for Helix rename and Vim visual rename.
Verification:
- `cargo check -p editor`
- `cargo fmt --check --package editor --package vim`
- `git diff --check -- crates\editor\src\editor.rs
crates\vim\src\test.rs`
- `test::test_rename`
- `test::test_helix_rename_uses_visible_cursor_position`
- `test::test_visual_rename_uses_visible_cursor_position`
Release Notes:
- Fixed Helix mode rename when the cursor is visually on the last
character of a symbol.
---------
Co-authored-by: dino <dinojoaocosta@gmail.com>
# Objective
The objective is to improve Helix's default keymap within Zed as a few
are still missing.
These are all [default
keymaps](https://docs.helix-editor.com/keymap.html) i was using within
Helix but dissapointed they weren't working in Zed
There's more info in [Are we Helix
yet?](https://github.com/zed-industries/zed/discussions/33580#top)
## Solution
- Add `] g` and `[ g` for hunk navigation in helix mode, in helix this
is go to next/previous change which maps nicely to Zed's go to
next/previous hunk. (it was set to `c` here but this is incorrect and
doesn't match Helix's keymap.
- Add `alt-b` and `alt-e` for larger syntax node navigation in helix
mode, i use this a few times to go to the top of a function within the
body and Zed doesn't have it mapped.
- Add `] space` and `[ space` for inserting empty lines in helix mode.
This one was incorrectly implemented previously, after the `space` Zed
is waiting for input. It needs to be a direct chord added rather than on
`helix_next` mode.
- This means the space binding from the helix_next operator context is
redundant, so ive removed it
- Add `*` to use selection for find in helix mode. Helix mode is
slightly different and doesn't "go to next" on `*`, instead that becomes
the `/` register. This is pretty fundamental to helix navigation so
should be ported to Zed also.
- Move `] d` and `[ d` diagnostics navigation into helix_normal context.
Vim was already using this one but it wasn't shared with Helix. I've
moved it to the shared Vim and Helix block.
## Testing
I've tested these changes with a local build and each one works as
expected
## 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:
- Added `alt-b`/`alt-e` in Helix mode to move to the start/end of the
larger syntax node.
- Added `*` in Helix mode to set the current selection for search.
- Fixed Helix `[`/`]` navigation so `c` goes to the previous/next
comment and `g` to the previous/next hunk, and single-key follow-ups
like `g` no longer hang.
---------
Co-authored-by: dino <dinojoaocosta@gmail.com>
While exploring the `vim` crate, I found that `ShellCommand` is
registered twice with identical closure bodies in
`crates/vim/src/command.rs`
[L331-L357](https://github.com/zed-industries/zed/blob/main/crates/vim/src/command.rs#L331-L357)
. This PR removes the redundant code block to clean up.
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:
- N/A
Co-authored-by: dino <dinojoaocosta@gmail.com>
The recent "pickers with previews" overhaul left the picker
sizing/presentation API spread across several overlapping knobs that
every call site had to set correctly — and many didn't, causing pickers
across the app to render at the wrong width, lose their container, or
stop dismissing. This PR consolidates that surface into a small,
hard-to-misuse API and makes correct sizing the default.
Net effect: a plain `Picker::uniform_list(delegate, …)` now renders
correctly out of the box (standard width, standard max-height, shrinks
to fit, dismisses properly), and the ~35 call sites only specify what
genuinely differs.
## API changes
**Presentation** — three overlapping booleans (`is_modal`, `is_popover`,
`is_resizable`) collapsed into one enum, with resizability living inside
the only variant where it's meaningful:
```rust
enum Presentation {
Modal { resizable: bool }, // own chrome, dismisses on blur, optionally resizable
Popover, // own chrome, dismisses on blur, never resizable
Embedded, // host container owns chrome + dismissal
}
```
- `modal(bool)` is **removed** in favor of explicit, self-documenting
builders:
- *(default)* → `Modal` (resizable iff it has a preview)
- `.popover()` → `Popover` (menu-attached surfaces)
- `.embedded()` → `Embedded` (pickers nested in a larger modal/view)
- Dynamic callers use `.when(cond, Picker::embedded)` (added `impl
FluentBuilder for Picker`).
**Sizing** — preview-vs-not now drives everything; the manual padding
knob is gone:
| Before | After |
|---|---|
| `vertical_padding` field + `no_vertical_padding()` | removed — derived
from whether a preview is visible |
| `height(...)` (ambiguous: fixed vs max) | `max_height(...)` (plain
pickers shrink-to-fit, capped here) |
| `minimum_results_width(...)` | removed — a plain picker's min width
tracks its opening width; preview pickers use standard internal pane
mins |
| default size = 60% viewport | default = `DEFAULT_MODAL_WIDTH` (34rem)
× `DEFAULT_MODAL_MAX_HEIGHT` (24rem, max) |
| resize handles gated on `is_modal` | gated on `is_resizable` (new
`resizable(bool)` builder; auto-`true` for preview pickers) |
Call sites now only override the exceptions: narrow popover selectors
(`initial_width`), the taller outline view (`max_height`), and preview
pickers (constructed via `*_with_preview`).
## Behavior fixes
- **Wrong widths everywhere**: pickers were falling back to
60%-of-viewport because the original migration set
`minimum_results_width` but never `initial_width`. Fixed at the source
via the new defaults.
- **Popovers had no container and wouldn't dismiss**: `is_modal=false`
was suppressing both the elevated background *and* blur-dismiss. Split
out so popovers keep their chrome and dismiss on click-away/escape. This
fixed the agent-panel model/profile selectors, sidebar recent projects,
and the settings theme/font/icon/ollama pickers (which were incorrectly
using `modal(false)`).
- **Sidebar recent projects stretched to full height**: was missing the
shrink-to-fit behavior; now capped and content-sized like other
popovers.
- **Preview crash**: removed an over-strict `debug_assert!` that
panicked when previewing an empty file (`message == None && editor
empty` is valid).
- **Preview-aware default size**: pickers open at standard width with
the preview hidden, and expand to the larger "telescope" size when a
preview is shown. Fixes the text finder rendering super-wide by default,
and makes the file finder expand (rather than cram its results) when you
toggle the preview.
---
Release Notes:
- N/A
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#52588
Release Notes:
- Fixed insert line above out of an scope
Co-authored-by: Yara 🏳️⚧️ <git@yara.blue>
Overhauls Zed's pickers to make them resizable and give them a preview.
Closes#8279
### Background
The most requested Zed feature has the last year has been a [Telescope
like search box](https://github.com/zed-industries/zed/issues/8279)
[discussion](https://github.com/zed-industries/zed/discussions/22581).
To understand why this is so popular we need to understand search can
serve thee goals:
- Navigation: fuzzy search is faster & easier then clicking in a file
tree
- Exploration: example, find a function by a word in its doc comment
- Collecting: example, getting a list of functions to change
The project search which shows results in a multibuffer is the perfect
way to operate on a list of items. Navigation and Exploration need a lot
of context around each result and offer fast navigation between them.
For both of these live searching is also critical.
The `telescope UI` is a picker with a preview to the right or below.
It's offered in various editors and IDE's most famously Neovim (through
the Telescope plugin), IntelliJ (natively), Helix (natively) and of
course VScode (plugins) and it's _many_ forks.
While having a UI like that for text search (our project search) is most
requested the UX pattern is applied widely, from `find_all_references`
to `bookmarks`. It enhances most pickers. Note that we have over 50
different picker modals!
The community has tried to build something like this for Zed:
- https://github.com/zed-industries/zed/pull/44530
- https://github.com/zed-industries/zed/pull/45307
- https://github.com/zed-industries/zed/pull/46478
- https://github.com/zed-industries/zed/pull/43790
These all became huge PR's that we could not merge for various reasons.
This is a really hard feature to integrate in Zed!
This PR got started as https://github.com/zed-industries/zed/pull/46478
and supercedes that.
### Design
- Extend pickers to support an optional preview with minimal changes to
the pickers themselves.
- Make pickers resizable.
- Complement the existing search do not replace it by having both UI's
share the underlying search and allow freely switching between them.
- Allow extending the preview to things other then files.
- Maintain a clean design on all the pickers.
### Heigh level Implementation overview
- Adds an `Option<Preview>` to `Picker`
- Gives `PickerDelegate` a method to communicate a preview to the Picker
- Overhaul the way pickers are drawn to allow for resizing them.
Implemented on the `Shape` and `SizeBouds` structs.
- Adds a high level way to draw the `footer` and `editor` so we do not
need to change much to the pickers.
- Adds a new text finder Picker
- Adds a way to take a running search from project search and hand it to
the text finder Picker and the other way round
- Give the file finder a preview
### Next steps
A more detailed list and how to help out will be added to the tracking
issue for [Pickes with
previews](https://github.com/zed-industries/zed/issues/56037)
- Add more previews to more pickers!
- Enable selectioning multiple items in pickers and performing actions
on those
- Open selected items in a multibuffer
- Add a way to restore the last picker
- Make popovers (picker attached to some menu) resizable as 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
TODO (will be done post merge)
---
Release Notes:
- Added resizing via dragging to all picker modals.
- Added a preview to the File finder, the preview can be to the right or
below.
- Added a Text finder picker with a preview as alternative project
search UI. The search is shared and allowes switch between UIs while
running.
---------
Co-authored-by: ozacod <47009516+ozacod@users.noreply.github.com>
Co-authored-by: ozacod <ozacod@users.noreply.github.com>
Co-authored-by: Danilo Leal <daniloleal09@gmail.com>
# Objective
- This PR fixed the `gg` and `ge` motion in Helix mode to match the
behavoir from Helix. Fixes#56702
## Solution
- The solution is to add custom handling for the StartOfDocument and
EndOfDocument Motions in normal and select mode. For both cases, column
0 is hard coded in the DisplayPoint for the destination of the motion.
## Testing
- Did you test these changes? If so, how?
Yes, I added unit tests which pass and also manually tested the `gg` and
`ge` motions in the new build.
- Are there any parts that need more testing?
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
1. Enable Helix mode in the settings
2. Open a file with multiple lines
3. Move to the middle of the file
4. Press `gg` and `ge`
5. Cursor should move to start or end of file at column 0
6. Same for Select mode
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
I only tested on Linux (Fedora). Since the changes are not platform
specific, I don't think more testing is necessary, but always welcome.
## 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 `gg` and `ge` motions to jump to the first character on the line
and match Helix exactly.
---------
Co-authored-by: dino <dinojoaocosta@gmail.com>
In vim, `c {count} w` diverges from the default `w` motion behavior: For
change operations, the `w` motion will be treated like the `e` motion if
the cursor is on a word, preserving whitespace after the N-th word. In
zed, this special case was only implemented for a count of 1, falling
back to incorrectly using the `w` motion if the count is greater than 1.
This PR generalizes this implementation to handle this special case for
any count.
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#56563.
Release Notes:
- Fixed: vim `cw` with count greater than 1 not preserving whitespace
correctly
---------
Co-authored-by: dino <dinojoaocosta@gmail.com>
# Objective
Fixes#58736
Pause the debugger on a breakpoint, switch your theme, and the active
debug line keeps its old highlight color until you step again or restart
Zed.
## Solution
The highlight stores a concrete color grabbed from the theme back when
`go_to_active_debug_line` ran. A theme switch goes through
`theme_changed`, which refreshes brackets, semantic tokens, and outline
symbols but never re-applies that highlight, so it stays stale.
Re-running `go_to_active_debug_line` from `theme_changed` re-resolves
the color against the current theme.
## Testing
Added a regression test in `debugger_ui` that stops at a debug line,
swaps the theme's `editor.debugger_active_line.background`, and checks
the highlight follows. It fails on `main` and passes with the fix.
Also tested by hand on Windows: started a debugpy session, paused at a
breakpoint, switched themes from the theme selector, and watched the
active line recolor live without stepping or restarting.
## 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
- [x] Performance impact has been considered and is acceptable
## Showcase
Paused at a breakpoint, switching themes from the theme selector.
| Before | After |
| --- | --- |
|
https://github.com/user-attachments/assets/653a7e1b-3a99-4316-b1c9-b16ed7a7a8ba
|
https://github.com/user-attachments/assets/22a4c876-30f2-44c5-aad9-0f860639074c
|
---
Release Notes:
- Fixed the active debug line color not updating when switching themes
while the debugger is paused
([#58736](https://github.com/zed-industries/zed/issues/58736)).
---------
Co-authored-by: dino <dinojoaocosta@gmail.com>
The work introduced in https://github.com/zed-industries/zed/pull/54496
updated the `command_aliases` schema, adding support for auto-completion
action names when editing the settings file. However, it didn't take
into consideration the case where the user is simply creating an alias
to an arbitrary string.
These changes introduce a new `CommandAliasTarget` newtype for which the
json schema is either a registered action name, from `ActionName` or any
arbitrary string, as those are supported by the `command_aliases`
setting.
Updating the `ActionName` schema to accept any arbitrary string would
break the guarantees we have on the keymap binding schema, so that's why
a new schema was introduced.
Lastly, trying to set `CommandAliasTarget::json_schema` to a simply
`anyOf` with either the registered action name or a string that is not a
registered action name, like shown below, broke deprecation warnings,
hence why we're still doing the approach of only building
`CommandAliasTarget` at runtime.
```json
{
"anyOf": [
{ "$ref": "#/$defs/ActionName" },
{ "type": "string", "not": {
"$ref": "#/$defs/ActionName"
}},
]
}
```
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 validation of `command_aliases` setting to avoid showing
warnings when aliasing to an arbitrary string
Closes#55170
Fixes Helix mode undo selection history after `d` deletes the character
under an empty cursor. Previously, `d` temporarily expanded the cursor
to a one-character selection before deleting, and undo restored that
temporary selection. When the deleted character was a newline, pressing
`x` after undo selected additional line which was wrong.
This preserves the original Helix selection as the undo-restored
selection while keeping the existing delete behavior unchanged.
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 Helix mode selecting one extra line after undoing a newline
delete
Co-authored-by: Tom Houlé <13155277+tomhoule@users.noreply.github.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 #ISSUE
Release Notes:
- N/A or Added/Fixed/Improved ...
Finally continuing from PR #35200:
I adapted the fix to the changed find_target() logic and added more
tests for version strings like `0.82.46`.
This is a different but similar fix compared to #47356 for helix mode -
not sure if this can and should be unified?
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)
(should not affect UI at all)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable
Closes#35193
Release Notes:
- Fixed vim's increment (`ctrl-a`) and decrement (`ctrl-x`) commands
skipping the number under the cursor in dotted strings like version
numbers (e.g. `0.81.46`) and hyphened date strings (e.g. `2015-02-01`)
---------
Co-authored-by: Stefan Bethge <kjyv@users.noreply.github.com>
Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
Co-authored-by: dino <dinojoaocosta@gmail.com>
Closes [#58343](<https://github.com/zed-industries/zed/issues/58343>)
This crash happened because Helix paste restored selection using the raw
clipboard text length, but buffer edits normalize CRLF line endings to
LF before inserting. When pasting CRLF text at or near EOF, the restored
selection could extend past the normalized snapshot length and panic in
`MutableSelectionsCollection::select_ranges`. The fix normalizes the
text before measuring it for selection restoration and adds regression
coverage for CRLF paste in Helix mode.
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 a crash that could occur when pasting at the end of a file in
Helix mode
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:
- N/A
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#54209
Release Notes:
- Fixed vim `%` (matching bracket) motion not working in multibuffers
---------
Co-authored-by: Cole Miller <cole@zed.dev>
Co-authored-by: zed-zippy[bot] <234243425+zed-zippy[bot]@users.noreply.github.com>
Closes#56493
In Helix select mode, pressing `a` after a selection (e.g. `v a`) placed
the cursor one column too far to the right.
Bound `a` to `vim::HelixAppend` in the `helix_select` keymap so it
matches the behavior in `helix_normal`, and added a regression test for
the `v a` case.
Release Notes:
- Fixed cursor placement after pressing `a` in Helix select mode.
---------
Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com>
Closes#47251
Fix dot (`.`) repeat not correctly repeating the last change after
replaying a macro (`@register`)
([#47251](https://github.com/zed-industries/zed/issues/47251))
When replaying a macro that contains text insertions,
`replay_insert_event` calls `handle_input` directly and never emits
`InputHandled`, so the `observe_insertion` subscription never fires.
This left the dot register stale — `.` after `@register` would repeat an
earlier change instead of the last one made by the macro.
Fix by calling `observe_insertion` explicitly in the
`ReplayableAction::Insertion` branch of `Replayer::next`.
Release Notes:
- Fixed dot (`.`) repeat not repeating the last change made by a macro
(`@register`).
---------
Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com>
Resolves https://github.com/zed-industries/zed/issues/57522
This diff fixes `r` in Helix select mode. The keybinding already pushed
the replace operator in `helix_select`, but when the replacement
character was typed, the operator dispatch only handled `HelixNormal`,
so selected text in `HelixSelect` fell through and cleared the operator
without editing the buffer.
With this change, Helix select mode uses the same `helix_replace` path
as Helix normal mode. Multi-character selections now replace each
selected grapheme with the typed character and return to Helix normal
mode, matching the existing behaviour for Helix normal selections.
Release Notes:
- Fixed `r` not replacing multi-character selections in Helix select
mode.
Resolves https://github.com/zed-industries/zed/issues/57486
This diff fixes `g w` after selecting lines with `x` in Helix mode. `x`
leaves Zed in Helix normal mode with a non-empty selection, but jump
target collection treated non-visual selections as ranges to skip. As a
result, words on the selected line did not receive jump labels.
With this change, Helix normal mode keeps existing selection ranges
eligible for jump targets, matching Helix's behavior where normal mode
can still carry selections. The regression covers `x` followed by `g w`
targeting a word inside the selected line.
Release Notes:
- Fixed `g w` not targeting words on lines selected with `x` in Helix
mode.
---------
Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com>
The cmd_f_search flag introduced in #51073 was never cleared when
switching to vim-style search commands, causing collapse_matches to
remain false and match ranges to appear as visual selections.
Reset cmd_f_search when n/N or */# are used, restore Normal mode if
Visual was entered due to the non-collapsed selection, and fix an early
return in visual select_match that leaked collapse_matches.
Fixes#53896
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: Conrad Irwin <conrad.irwin@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
## Summary
Prevent undo grouping when an LSP completion includes extra edits so
that the completion and its extra edits are applied and reverted
atomically.
## Problem
When applying an LSP completion that also applies extra edits, the
editor may merge that completion into the surrounding undo group or
split the transaction while waiting for edits, causing undo to leave the
buffer in an inconsistent state.
## Solution
* Always block undo merging for completions
Closes #ISSUE
Release Notes:
- Prevent undo grouping when any LSP completion
Closes#55619
### Summary
- Route `buffer_search::UseSelectionForFind` through
`BufferSearchBar::deploy` instead of updating the query editor directly.
- Add an explicit seed-query override to `deploy`, so the Cmd-E action
can force `SeedQuerySetting::Always` while regular deploy callers
continue to pass `None` and respect the user’s
`seed_search_query_from_cursor` setting.
- By going through `deploy`, Cmd-E now also runs the search path that
keeps buffer-search navigation state in sync:
- shows/initializes the search bar for the active searchable item
- applies the seeded query via `search_suggested`
- calls `search`, which updates the query editor, search options, active
search query, search history, and macOS find pasteboard
- refreshes `searchable_items_with_matches` and `active_match_index`
- activates the current match after the search completes
- This ensures the subsequent Cmd-G action has the expected active
query, match list, search token, and active match index to select the
next result.
- Add a macOS-only end-to-end regression test using the default macOS
keymap with `simulate_keystrokes("cmd-e")` and
`simulate_keystrokes("cmd-g")`.
### Validation
- `cargo test -p search test_cmd_e_then_cmd_g_uses_selection_for_find`
- `cargo fmt --check --package search --package zed_actions`
- `./script/check-keymaps`
- `cargo check -p search`
- `cargo check -p workspace`
- `cargo check -p vim`
Release Notes:
- Fixed macOS Cmd-E/Cmd-G find behavior so Cmd-E seeds find from the
cursor or selection and Cmd-G advances through the newly seeded matches.
Closes#55481
Adds Vim-mode access to the existing Helix jump-to-word overlay via `g
z`. We use `g z` because it is currently unassigned in Vim mode, while
`g w` is already used for rewrap.
Most of the implementation lives in `helix.rs` because the existing jump
overlay, label generation, and Helix/Vim modal behavior are currently
intertwined there. This keeps the change small and reuses the existing
navigation overlay logic instead of doing a broader refactor.
In Vim normal mode, jump labels behave like a cursor motion: selecting a
label moves the cursor to the start of the target word without selecting
it. In Vim visual mode, jump labels extend the selection like a Vim
word-start motion, preserving Vim’s inclusive visual-selection behavior.
Self-Review Checklist:
- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content 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:
- Added Vim-mode jump-to-word navigation on `g z`.
Part of #48241 (`dsq` still needs to be implemented, I can try to do in
another PR if+when this is merged)
AnyBrackets was already supported, and these various surrounds were
supported with other vim motions, this just brings parity for "change
surrounds".
Also adds MiniBrackets support since it works the same way as MiniQuotes
does.
Most of this change is just test cases for vim edits with `csq` + `csb`,
using the keybinds described in the docs:
https://zed.dev/docs/vim#any-bracket-functionality
Also did a slight refactor to reuse some constants for supported pairs,
for consistency.
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
- [x] Aligned any UI changes with the [UI
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
Release Notes:
- Fixed vim `change surrounds` for MiniQuotes, MiniBrackets, and
AnyQuotes
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 #ISSUE
Release Notes:
- Added a setting
[vim.show_edit_predictions_in_normal_mode](zed://settings/vim.show_edit_predictions_in_normal_mode)
to control whether edit predictions are shown in normal mode.
Closes#24820
This PR fixes the bug specified in issue
https://github.com/zed-industries/zed/issues/24820, now the matching
function checks if the cursor is above a comment or a directive before
defaulting to a bracket range as neovim does.
It also fixes fixes the `line_end` calculations so that when `%` is
pressed inside a bracket range
https://github.com/user-attachments/assets/f59daa6f-9769-45e8-bb8c-2d533470b59d
Release Notes:
- `fn matching()` checks for `preprocessor directives` or `comments`
before defaulting to any bracket range.
- In `fn matching()`line_end calculations avoid expanding a blank
current line into start..EOF.
cc @SomeoneToIgnore
## Summary
Follow-up to https://github.com/zed-industries/zed/discussions/55352,
where the conclusion was to split `editor.rs` incrementally by topic
instead of all at once.
This mechanically extracts editor config and reflow-related code into
`crates/editor/src/config.rs` and `crates/editor/src/rewrap.rs`, while
preserving existing behavior and keeping externally-used APIs public
where needed.
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:
- N/A