From aedd24ac2ee44a50b451f34fdc94b53f9a5de192 Mon Sep 17 00:00:00 2001 From: Dino Date: Tue, 21 Oct 2025 12:23:00 +0100 Subject: [PATCH] vim: Fix hang in visual block motion (#40723) The `vim::visual::Vim.visual_block_motion` method was recently updated (https://github.com/zed-industries/zed/pull/39355) in order to jump between buffer rows instead of display rows. However, with this now being the case, the `break` condition was never met when the motion was horizontal rather than vertical and soft wrapped lines were used. As such, this commit udpates the condition to ensure it's always reached, preventing the hanging from happening. Release Notes: - Fixed hang in Vim's visual block motions when updating selections --------- Co-authored-by: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> --- crates/vim/src/visual.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/crates/vim/src/visual.rs b/crates/vim/src/visual.rs index bce49eb7d4..59555205d9 100644 --- a/crates/vim/src/visual.rs +++ b/crates/vim/src/visual.rs @@ -366,6 +366,8 @@ impl Vim { let mut selections = Vec::new(); let mut row = tail.row(); + let going_up = tail.row() > head.row(); + let direction = if going_up { -1 } else { 1 }; loop { let laid_out_line = map.layout_row(row, &text_layout_details); @@ -396,13 +398,18 @@ impl Vim { selections.push(selection); } - if row == head.row() { + + // When dealing with soft wrapped lines, it's possible that + // `row` ends up being set to a value other than `head.row()` as + // `head.row()` might be a `DisplayPoint` mapped to a soft + // wrapped line, hence the need for `<=` and `>=` instead of + // `==`. + if going_up && row <= head.row() || !going_up && row >= head.row() { break; } - // Move to the next or previous buffer row, ensuring that - // wrapped lines are handled correctly. - let direction = if tail.row() > head.row() { -1 } else { 1 }; + // Find the next or previous buffer row where the `row` should + // be moved to, so that wrapped lines are skipped. row = map .start_of_relative_buffer_row(DisplayPoint::new(row, 0), direction) .row();