From b631e813e42367d109c7ee2cd16c91e36a84b87a 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 f8ef8e32586ca11800b5d3872aafaead3275bd37..455061c22b2231847151d4d9c92a296075ae3593 100644 --- a/crates/vim/src/visual.rs +++ b/crates/vim/src/visual.rs @@ -369,6 +369,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); @@ -399,13 +401,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 = start_of_relative_buffer_row(map, DisplayPoint::new(row, 0), direction).row(); }