From 708852aa000963780f678c7189b681039a8bfcbf Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Thu, 6 Jul 2023 14:11:18 +0200 Subject: [PATCH 1/2] Clip left when finding preceding (line) boundary This fixes an issue that was causing `alt-left` to not move the cursor when it was located right after an inlay hint with a `Left` bias. --- crates/editor/src/movement.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/editor/src/movement.rs b/crates/editor/src/movement.rs index 523a0af964..e589337979 100644 --- a/crates/editor/src/movement.rs +++ b/crates/editor/src/movement.rs @@ -263,13 +263,13 @@ pub fn find_preceding_boundary( if let Some((prev_ch, prev_point)) = prev { if is_boundary(ch, prev_ch) { - return prev_point; + return map.clip_point(prev_point, Bias::Left); } } prev = Some((ch, point)); } - DisplayPoint::zero() + map.clip_point(DisplayPoint::zero(), Bias::Left) } /// Scans for a boundary preceding the given start point `from` until a boundary is found, indicated by the @@ -292,7 +292,7 @@ pub fn find_preceding_boundary_in_line( for (ch, point) in map.reverse_chars_at(from) { if let Some((prev_ch, prev_point)) = prev { if is_boundary(ch, prev_ch) { - return prev_point; + return map.clip_point(prev_point, Bias::Left); } } @@ -303,7 +303,7 @@ pub fn find_preceding_boundary_in_line( prev = Some((ch, point)); } - prev.map(|(_, point)| point).unwrap_or(from) + map.clip_point(prev.map(|(_, point)| point).unwrap_or(from), Bias::Left) } /// Scans for a boundary following the given start point until a boundary is found, indicated by the From 11ae99fbd6d953d9e89ee3821ef7be64ac8e9219 Mon Sep 17 00:00:00 2001 From: Kirill Bulatov Date: Thu, 6 Jul 2023 17:12:26 +0300 Subject: [PATCH 2/2] Add a test --- crates/editor/src/movement.rs | 80 ++++++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/crates/editor/src/movement.rs b/crates/editor/src/movement.rs index e589337979..e50d7d8306 100644 --- a/crates/editor/src/movement.rs +++ b/crates/editor/src/movement.rs @@ -406,8 +406,12 @@ pub fn split_display_range_by_lines( #[cfg(test)] mod tests { use super::*; - use crate::{test::marked_display_snapshot, Buffer, DisplayMap, ExcerptRange, MultiBuffer}; + use crate::{ + display_map::Inlay, test::marked_display_snapshot, Buffer, DisplayMap, ExcerptRange, + InlayId, MultiBuffer, + }; use settings::SettingsStore; + use util::post_inc; #[gpui::test] fn test_previous_word_start(cx: &mut gpui::AppContext) { @@ -505,6 +509,80 @@ mod tests { }); } + #[gpui::test] + fn test_find_preceding_boundary_with_inlays(cx: &mut gpui::AppContext) { + init_test(cx); + + let input_text = "abcdefghijklmnopqrstuvwxys"; + let family_id = cx + .font_cache() + .load_family(&["Helvetica"], &Default::default()) + .unwrap(); + let font_id = cx + .font_cache() + .select_font(family_id, &Default::default()) + .unwrap(); + let font_size = 14.0; + let buffer = MultiBuffer::build_simple(input_text, cx); + let buffer_snapshot = buffer.read(cx).snapshot(cx); + let display_map = + cx.add_model(|cx| DisplayMap::new(buffer, font_id, font_size, None, 1, 1, cx)); + + // add all kinds of inlays between two word boundaries: we should be able to cross them all, when looking for another boundary + let mut id = 0; + let inlays = (0..buffer_snapshot.len()) + .map(|offset| { + [ + Inlay { + id: InlayId::Suggestion(post_inc(&mut id)), + position: buffer_snapshot.anchor_at(offset, Bias::Left), + text: format!("test").into(), + }, + Inlay { + id: InlayId::Suggestion(post_inc(&mut id)), + position: buffer_snapshot.anchor_at(offset, Bias::Right), + text: format!("test").into(), + }, + Inlay { + id: InlayId::Hint(post_inc(&mut id)), + position: buffer_snapshot.anchor_at(offset, Bias::Left), + text: format!("test").into(), + }, + Inlay { + id: InlayId::Hint(post_inc(&mut id)), + position: buffer_snapshot.anchor_at(offset, Bias::Right), + text: format!("test").into(), + }, + ] + }) + .flatten() + .collect(); + let snapshot = display_map.update(cx, |map, cx| { + map.splice_inlays(Vec::new(), inlays, cx); + map.snapshot(cx) + }); + + assert_eq!( + find_preceding_boundary( + &snapshot, + buffer_snapshot.len().to_display_point(&snapshot), + |left, _| left == 'a', + ), + 0.to_display_point(&snapshot), + "Should not stop at inlays when looking for boundaries" + ); + + assert_eq!( + find_preceding_boundary_in_line( + &snapshot, + buffer_snapshot.len().to_display_point(&snapshot), + |left, _| left == 'a', + ), + 0.to_display_point(&snapshot), + "Should not stop at inlays when looking for boundaries in line" + ); + } + #[gpui::test] fn test_next_word_end(cx: &mut gpui::AppContext) { init_test(cx);