Skip to content

editor: Fix block cursor offset when selecting text#42837

Merged
dinocosta merged 3 commits intozed-industries:mainfrom
lennartkloock:fix-cursor-offset
Dec 15, 2025
Merged

editor: Fix block cursor offset when selecting text#42837
dinocosta merged 3 commits intozed-industries:mainfrom
lennartkloock:fix-cursor-offset

Conversation

@lennartkloock
Copy link
Contributor

@lennartkloock lennartkloock commented Nov 16, 2025

Closes #36677 and #20121

Problem

Vim visual mode and Helix selection mode both require the cursor to be on the last character of the selection. Until now, this was implemented by offsetting the cursor one character to the left whenever a block cursor is used. (Since the visual modes use a block cursor.)

if (cursor_shape == CursorShape::Block || cursor_shape == CursorShape::Hollow)

However, this oversees the problem that some users might want to use the block cursor without being in visual mode. Meaning that the cursor is offset by one character to the left even though Vim/Helix mode isn't even activated.

Solution

Since the Vim mode implementation is separate from the editor crate the solution is not as straightforward as just checking the current vim mode. Therefore this PR introduces a new Editor struct field called cursor_offset_on_selection. This field replaces the condition above and is set to true whenever the Vim mode is changed to a visual mode, and false otherwise.

If there is a better solution without having to add a new Editor field, let me know.

Release Notes:

  • Fixes block and hollow cursor being offset when selecting text

@cla-bot cla-bot bot added the cla-signed The user has signed the Contributor License Agreement label Nov 16, 2025
@lennartkloock lennartkloock changed the title editor: Fix block cursor offset on select editor: Fix block cursor offset when selecting text Nov 16, 2025
@dinocosta
Copy link
Member

Hey @lennartkloock , thank you for opening this Pull Request 👋

I'm wondering if I'm doing something wrong or testing the wrong cgghanges, but seems like these changes don't actually fix the reproduction steps shared in #36677 . Here's a screen recording of me comparing both the current Zed Nightly with your changes ▼

CleanShot.2025-11-25.at.12.37.06.mp4

In both cases I still see the issue with using shift-cmd-right not visually selecting all of the elements in the line. Are these changes trying to solve a different issue?

Also, not sure if it helps but we also have the editor::vim_flavor function that you can access from the editor, not sure if it helps but a solution where we don't need to add new fields would be preferred, as this also seems like we might just need to fix editor::SelectToEndOfLine and editor::SelectToBeginningOfLine when vim mode is enabled 🙂

@lennartkloock
Copy link
Contributor Author

lennartkloock commented Nov 25, 2025

Hey @lennartkloock , thank you for opening this Pull Request 👋

I'm wondering if I'm doing something wrong or testing the wrong cgghanges, but seems like these changes don't actually fix the reproduction steps shared in #36677 . Here's a screen recording of me comparing both the current Zed Nightly with your changes ▼
CleanShot.2025-11-25.at.12.37.06.mp4

In both cases I still see the issue with using shift-cmd-right not visually selecting all of the elements in the line. Are these changes trying to solve a different issue?

Also, not sure if it helps but we also have the editor::vim_flavor function that you can access from the editor, not sure if it helps but a solution where we don't need to add new fields would be preferred, as this also seems like we might just need to fix editor::SelectToEndOfLine and editor::SelectToBeginningOfLine when vim mode is enabled 🙂

The issue doesn't happen in Vim mode. To reproduce the problem you have to disable Vim mode and enable the block or hollow cursor. Thanks for pointing me to that function, I will look if it helps in this case.

Edit: I don't know if I'm missing something but I think both editor::SelectToEndOfLine and editor::SelectToBeginningOfLine are completely fine and work like expected, right?

Edit: nvm I just saw the other issue #38104 but seems like it's unrelated because it only happens in Vim mode

@lennartkloock
Copy link
Contributor Author

Unfortunately, the editor::vim_flavor function doesn't help here because we have to figure out not only if the editor is in Vim mode but also if it is in visual mode.

That said, what we could do is use editor::vim_flavor to check if it is in Vim mode and then use the cursor_shape field to determine if it is in visual mode but in my opinion that field shouldn't be used like that because it results in bugs like this one.

@dinocosta
Copy link
Member

The issue doesn't happen in Vim mode. To reproduce the problem you have to disable Vim mode and enable the block or hollow cursor.

Would you be able to share reproduction steps? I'm still having a hard time reproducing the issue that this Pull Request is attempting to fix 🙂

@aurexav

This comment was marked as spam.

@dinocosta
Copy link
Member

Has there been any progress? I’m really in need of this fix.

@aurexav If possible, can you share a small reproduction of the issue? Wanted to confirm that these changes actually fixed the issue but seems I was unable to reproduce the actual issue to check if it fixed it.

@aurexav
Copy link
Contributor

aurexav commented Dec 3, 2025

Has there been any progress? I’m really in need of this fix.

@aurexav If possible, can you share a small reproduction of the issue? Wanted to confirm that these changes actually fixed the issue but seems I was unable to reproduce the actual issue to check if it fixed it.

  1. Use block cursor
  2. Open a file
  3. Put cursor at the beginning of a line
  4. Press shift + end

Zed

image

Zed Underline

image

VSCode

image

And you can continue press right. And the cursor won't move to next line. The selection is completely wrong.

image

The memory level selection is correct but the visual is completely wrong.

@lennartkloock
Copy link
Contributor Author

Thanks for sharing the reproduction steps, I didn't have time yet. You can also see this when selecting text using your mouse.

@dinocosta
Copy link
Member

dinocosta commented Dec 5, 2025

@aurexav Thank you for sharing those steps! When you state "1. Use block cursor", do yo mean the following settings?

{
  "cursor_shape": "block",
}

If so, I just tested these changes, comparing how it behaves against the latest stable release and it appears the behavior for shift-end is still the same ▼

CleanShot.2025-12-05.at.10.28.57.mp4

The behavior of editor::SelectToEndOfLine does appear to be broken but it seems that the changes in this Pull Request don't actually fix it? Let me know if I'm missing something, thanks!

And you can continue press right. And the cursor won't move to next line. The selection is completely wrong.

If you have vim mode enabled, I believe this is meant to replicate vim's behavior, where if you're at the end of the line, pressing l will not continue the selection on the next line.

@lennartkloock
Copy link
Contributor Author

@aurexav Thank you for sharing those steps! When you state "1. Use block cursor", do yo mean the following settings?

{
  "cursor_shape": "block",
}

If so, I just tested these changes, comparing how it behaves against the latest stable release and it appears the behavior for shift-end is still the same ▼
CleanShot.2025-12-05.at.10.28.57.mp4

The behavior of editor::SelectToEndOfLine does appear to be broken but it seems that the changes in this Pull Request don't actually fix it? Let me know if I'm missing something, thanks!

And you can continue press right. And the cursor won't move to next line. The selection is completely wrong.

If you have vim mode enabled, I believe this is meant to replicate vim's behavior, where if you're at the end of the line, pressing l will not continue the selection on the next line.

I don't know if there is a misunderstanding here but it seems like you are still in Vim mode in your video. The issue that is fixed here only appears if you're NOT in Vim mode. Please disable Vim mode for the reproduction steps to work. (set "vim_mode": false in your settings file)

@aurexav
Copy link
Contributor

aurexav commented Dec 8, 2025

@aurexav Thank you for sharing those steps! When you state "1. Use block cursor", do yo mean the following settings?

{
  "cursor_shape": "block",
}

Yes.

If you have vim mode enabled, I believe this is meant to replicate vim's behavior, where if you're at the end of the line, pressing l will not continue the selection on the next line.

I'm a VIM hater. I never use that mode.

@lennartkloock
Copy link
Contributor Author

Here is a video I recorded demonstrating the issue. I hope that helps to further clarify it.

Settings are:

{
  "vim_mode": false,
  "cursor_shape": "block",
}
Screencast.From.2025-12-09.12-12-03.mp4

@dinocosta
Copy link
Member

Thank you for sharing @lennartkloock , was probably confusing what the real issue was but I've been able to reproduce it too! Will take a look at these changes shortly, likely during next week's Quality Week 🙂

Since we're already updating the vim's editor in that function, we can
avoid an extre call to `self.update_editor`.
@dinocosta dinocosta merged commit 5fe7fd9 into zed-industries:main Dec 15, 2025
23 checks passed
@github-project-automation github-project-automation bot moved this from Community PRs to Done in Quality Week – December 2025 Dec 15, 2025
dinocosta added a commit that referenced this pull request Dec 15, 2025
…Settings (#44889)

In a previous Pull Request, a new field was added to `editor::Editor`,
namely `cursor_offset_on_selection`, in order to control whether the
cursor representing the head of a selection should be positioned in the
last selected character, as we have on Vim mode, or after, like we have
when Vim mode is disabled.

This field would then be set by the `vim` crate, depending on the
current vim mode. However, it was noted that
`vim_mode_setting::VimModeSetting` already exsits and allows other
crates to determine whether Vim mode is enabled or not. Since we're
already checking `!range.is_empty()` in
`editor::element::SelectionLayout::new` we can then rely on simply
determining whether Vim mode is enabled to decide whether tho shift the
cursor one position to the left when making a selection.

As such, this commit removes the `cursor_offset_on_selection` field, as
well as any related methods in favor of a new `Editor.vim_mode_enabled`
method, which can be used to achieve the same behavior.

Relates to #42837 

Release Notes:

- N/A
@aurexav
Copy link
Contributor

aurexav commented Dec 16, 2025

Will this be included in Thursday's preview version?

CherryWorm pushed a commit to CherryWorm/zed that referenced this pull request Dec 16, 2025
…2837)

Vim visual mode and Helix selection mode both require the cursor to be
on the last character of the selection. Until now, this was implemented
by offsetting the cursor one character to the left whenever a block
cursor is used. (Since the visual modes use a block cursor.)

However, this oversees the problem that **some users might want to use
the block cursor without being in visual mode**. Meaning that the cursor
is offset by one character to the left even though Vim/Helix mode isn't
even activated.

Since the Vim mode implementation is separate from the `editor` crate
the solution is not as straightforward as just checking the current vim
mode. Therefore this PR introduces a new `Editor` struct field called
`cursor_offset_on_selection`. This field replaces the previous check 
condition and is set to `true` whenever the Vim mode is changed to a 
visual mode, and `false` otherwise.

Closes zed-industries#36677 and zed-industries#20121

Release Notes:

- Fixes block and hollow cursor being offset when selecting text

---------

Co-authored-by: dino <dinojoaocosta@gmail.com>
CherryWorm pushed a commit to CherryWorm/zed that referenced this pull request Dec 16, 2025
…Settings (zed-industries#44889)

In a previous Pull Request, a new field was added to `editor::Editor`,
namely `cursor_offset_on_selection`, in order to control whether the
cursor representing the head of a selection should be positioned in the
last selected character, as we have on Vim mode, or after, like we have
when Vim mode is disabled.

This field would then be set by the `vim` crate, depending on the
current vim mode. However, it was noted that
`vim_mode_setting::VimModeSetting` already exsits and allows other
crates to determine whether Vim mode is enabled or not. Since we're
already checking `!range.is_empty()` in
`editor::element::SelectionLayout::new` we can then rely on simply
determining whether Vim mode is enabled to decide whether tho shift the
cursor one position to the left when making a selection.

As such, this commit removes the `cursor_offset_on_selection` field, as
well as any related methods in favor of a new `Editor.vim_mode_enabled`
method, which can be used to achieve the same behavior.

Relates to zed-industries#42837 

Release Notes:

- N/A
@dinocosta
Copy link
Member

Will this be included in Thursday's preview version?

I believe so. We're planning on making new releases a little bit sooner this week, seeing as next week a lot of folks are going to be out of office 🙂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla-signed The user has signed the Contributor License Agreement

Projects

Development

Successfully merging this pull request may close these issues.

Block cursor position is inconsistent with highlighting

3 participants