Compare commits

...

4 Commits

Author SHA1 Message Date
Jakub Konka
4364afa6d2 Debug DisplaySnapshot and clip_at_line_ends 2025-11-24 16:14:31 +01:00
俺不叫化咕龙
9a09ed55bd Fixed unused variable warning. 2025-11-24 16:14:31 +01:00
俺不叫化咕龙
8e5d71bcd4 run CI. 2025-11-24 16:14:31 +01:00
俺不叫化咕龙
de384cb56b Attempt to handle EndOfLine motion in Helix mode. 2025-11-24 16:14:31 +01:00
2 changed files with 112 additions and 2 deletions

View File

@@ -776,7 +776,7 @@ pub struct DisplaySnapshot {
block_snapshot: BlockSnapshot,
text_highlights: TextHighlights,
inlay_highlights: InlayHighlights,
clip_at_line_ends: bool,
pub clip_at_line_ends: bool,
masked: bool,
diagnostics_max_severity: DiagnosticSeverity,
pub(crate) fold_placeholder: FoldPlaceholder,
@@ -1183,8 +1183,10 @@ impl DisplaySnapshot {
pub fn clip_point(&self, point: DisplayPoint, bias: Bias) -> DisplayPoint {
let mut clipped = self.block_snapshot.clip_point(point.0, bias);
println!(" clipped={clipped:?}");
if self.clip_at_line_ends {
clipped = self.clip_at_line_end(DisplayPoint(clipped)).0
clipped = self.clip_at_line_end(DisplayPoint(clipped)).0;
println!(" clipped(E)={clipped:?}");
}
DisplayPoint(clipped)
}
@@ -1196,6 +1198,11 @@ impl DisplaySnapshot {
pub fn clip_at_line_end(&self, display_point: DisplayPoint) -> DisplayPoint {
let mut point = self.display_point_to_point(display_point, Bias::Left);
println!(
" point.column={}, buffer_line_len={}",
point.column,
self.buffer_snapshot().line_len(MultiBufferRow(point.row))
);
if point.column != self.buffer_snapshot().line_len(MultiBufferRow(point.row)) {
return display_point;
}

View File

@@ -263,6 +263,54 @@ impl Vim {
cx: &mut Context<Self>,
) {
match motion {
Motion::EndOfLine { display_lines } => {
// In Helix mode, EndOfLine should position cursor ON the last character,
// not after it. We need special handling it.
self.update_editor(cx, |_, editor, cx| {
let text_layout_details = editor.text_layout_details(window);
editor.change_selections(Default::default(), window, cx, |s| {
s.move_with(|map, selection| {
let goal = selection.goal;
let mut cursor = if selection.is_empty() || selection.reversed {
selection.head()
} else {
movement::left(map, selection.head())
};
println!(">>>");
println!(" clip_at_line_ends={}", map.clip_at_line_ends);
println!(" cursor={cursor:?}");
let times = times.unwrap_or(1);
if times > 1 {
cursor =
map.start_of_relative_buffer_row(cursor, times as isize - 1);
}
let point = if display_lines {
map.clip_point(
DisplayPoint::new(cursor.row(), map.line_len(cursor.row())),
Bias::Left,
)
} else {
let nnn = map.next_line_boundary(cursor.to_point(map));
println!(" nnn={nnn:?}");
map.clip_point(
map.next_line_boundary(cursor.to_point(map)).1,
Bias::Left,
)
};
// let (point, _goal) = motion
// .move_point(map, cursor, goal, times, &text_layout_details)
// .unwrap_or((cursor, goal));
println!(" point={point:?}");
println!("<<<");
// Move left by one character to position on the last character
let adjusted_point = movement::saturating_left(map, point);
selection.collapse_to(adjusted_point, SelectionGoal::None)
})
});
});
}
Motion::NextWordStart { ignore_punctuation } => {
self.helix_find_range_forward(times, window, cx, |left, right, classifier| {
let left_kind = classifier.kind_with(left, ignore_punctuation);
@@ -1493,4 +1541,59 @@ mod test {
Mode::Insert,
);
}
#[gpui::test]
async fn test_g_l_end_of_line(cx: &mut gpui::TestAppContext) {
let mut cx = VimTestContext::new(cx, true).await;
cx.enable_helix();
// Test g l moves to last character, not after it
cx.set_state("hello ˇworld!", Mode::HelixNormal);
cx.simulate_keystrokes("g l");
cx.assert_state("hello worldˇ!", Mode::HelixNormal);
// Test with Chinese characters, test if work with UTF-8?
cx.set_state("ˇ你好世界", Mode::HelixNormal);
cx.simulate_keystrokes("g l");
cx.assert_state("你好世ˇ界", Mode::HelixNormal);
// Test with end of line
cx.set_state("endˇ", Mode::HelixNormal);
cx.simulate_keystrokes("g l");
cx.assert_state("enˇd", Mode::HelixNormal);
// Test with empty line
cx.set_state(
indoc! {"
hello
ˇ
world"},
Mode::HelixNormal,
);
cx.simulate_keystrokes("g l");
cx.assert_state(
indoc! {"
hello
ˇ
world"},
Mode::HelixNormal,
);
// Test with multiple lines
cx.set_state(
indoc! {"
ˇfirst line
second line
third line"},
Mode::HelixNormal,
);
cx.simulate_keystrokes("g l");
cx.assert_state(
indoc! {"
first linˇe
second line
third line"},
Mode::HelixNormal,
);
}
}