From baeb7d27b8c1121fceb9908253103457ea1a7ddc Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 21 Mar 2022 13:58:16 -0600 Subject: [PATCH] Clarify word movement function names and improve test coverage Co-Authored-By: Keith Simmons --- crates/editor/src/editor.rs | 13 ++--- crates/editor/src/movement.rs | 102 ++++++++++++++++++++++++++++++---- 2 files changed, 96 insertions(+), 19 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 30888d8a408ada78170e6dd6a39979392e085fe4..c3858b434993820b6458825532d52ec8b09b734c 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -3480,7 +3480,7 @@ impl Editor { let mut selections = self.local_selections::(cx); for selection in &mut selections { let head = selection.head().to_display_point(&display_map); - let cursor = movement::prev_word_boundary(&display_map, head).to_point(&display_map); + let cursor = movement::previous_word_start(&display_map, head).to_point(&display_map); selection.start = cursor.clone(); selection.end = cursor; selection.reversed = false; @@ -3498,7 +3498,7 @@ impl Editor { let mut selections = self.local_selections::(cx); for selection in &mut selections { let head = selection.head().to_display_point(&display_map); - let cursor = movement::prev_word_boundary(&display_map, head).to_point(&display_map); + let cursor = movement::previous_word_start(&display_map, head).to_point(&display_map); selection.set_head(cursor); selection.goal = SelectionGoal::None; } @@ -3517,7 +3517,7 @@ impl Editor { if selection.is_empty() { let head = selection.head().to_display_point(&display_map); let cursor = - movement::prev_word_boundary(&display_map, head).to_point(&display_map); + movement::previous_word_start(&display_map, head).to_point(&display_map); selection.set_head(cursor); selection.goal = SelectionGoal::None; } @@ -3536,7 +3536,7 @@ impl Editor { let mut selections = self.local_selections::(cx); for selection in &mut selections { let head = selection.head().to_display_point(&display_map); - let cursor = movement::next_word_boundary(&display_map, head).to_point(&display_map); + let cursor = movement::next_word_end(&display_map, head).to_point(&display_map); selection.start = cursor; selection.end = cursor; selection.reversed = false; @@ -3554,7 +3554,7 @@ impl Editor { let mut selections = self.local_selections::(cx); for selection in &mut selections { let head = selection.head().to_display_point(&display_map); - let cursor = movement::next_word_boundary(&display_map, head).to_point(&display_map); + let cursor = movement::next_word_end(&display_map, head).to_point(&display_map); selection.set_head(cursor); selection.goal = SelectionGoal::None; } @@ -3572,8 +3572,7 @@ impl Editor { for selection in &mut selections { if selection.is_empty() { let head = selection.head().to_display_point(&display_map); - let cursor = - movement::next_word_boundary(&display_map, head).to_point(&display_map); + let cursor = movement::next_word_end(&display_map, head).to_point(&display_map); selection.set_head(cursor); selection.goal = SelectionGoal::None; } diff --git a/crates/editor/src/movement.rs b/crates/editor/src/movement.rs index 5951e2c20db8b9f675f0d6a25afb7e5590e8dc7b..a090d8dde2420c5073e5786847b446e768ebd149 100644 --- a/crates/editor/src/movement.rs +++ b/crates/editor/src/movement.rs @@ -132,7 +132,7 @@ pub fn line_end( } } -pub fn prev_word_boundary(map: &DisplaySnapshot, mut point: DisplayPoint) -> DisplayPoint { +pub fn previous_word_start(map: &DisplaySnapshot, mut point: DisplayPoint) -> DisplayPoint { let mut line_start = 0; if point.row() > 0 { if let Some(indent) = map.soft_wrap_indent(point.row() - 1) { @@ -171,7 +171,7 @@ pub fn prev_word_boundary(map: &DisplaySnapshot, mut point: DisplayPoint) -> Dis boundary } -pub fn next_word_boundary(map: &DisplaySnapshot, mut point: DisplayPoint) -> DisplayPoint { +pub fn next_word_end(map: &DisplaySnapshot, mut point: DisplayPoint) -> DisplayPoint { let mut prev_char_kind = None; for c in map.chars_at(point) { let char_kind = char_kind(c); @@ -297,6 +297,84 @@ mod tests { ); } + #[gpui::test] + fn test_previous_word_start(cx: &mut gpui::MutableAppContext) { + fn assert(marked_text: &str, cx: &mut gpui::MutableAppContext) { + let (snapshot, display_points) = marked_snapshot(marked_text, cx); + dbg!(&display_points); + assert_eq!( + previous_word_start(&snapshot, display_points[1]), + display_points[0] + ); + } + + assert("\n| |lorem", cx); + assert(" |lorem|", cx); + assert(" |lor|em", cx); + assert("\nlorem\n| |ipsum", cx); + assert("\n\n|\n|", cx); + assert(" |lorem |ipsum", cx); + assert("lorem|-|ipsum", cx); + assert("lorem|-#$@|ipsum", cx); + assert("|lorem_|ipsum", cx); + } + + #[gpui::test] + fn test_next_word_end(cx: &mut gpui::MutableAppContext) { + fn assert(marked_text: &str, cx: &mut gpui::MutableAppContext) { + let (snapshot, display_points) = marked_snapshot(marked_text, cx); + assert_eq!( + next_word_end(&snapshot, display_points[0]), + display_points[1] + ); + } + + assert("\n| lorem|", cx); + assert(" |lorem|", cx); + assert(" lor|em|", cx); + assert(" lorem| |\nipsum\n", cx); + assert("\n|\n|\n\n", cx); + assert("lorem| ipsum| ", cx); + assert("lorem|-|ipsum", cx); + assert("lorem|#$@-|ipsum", cx); + assert("lorem|_ipsum|", cx); + } + + // Returns a snapshot from text containing '|' character markers with the markers removed, and DisplayPoints for each one. + fn marked_snapshot( + text: &str, + cx: &mut gpui::MutableAppContext, + ) -> (DisplaySnapshot, Vec) { + let mut marked_offsets = Vec::new(); + let chunks = text.split('|'); + let mut text = String::new(); + + for chunk in chunks { + text.push_str(chunk); + marked_offsets.push(text.len()); + } + marked_offsets.pop(); + + let tab_size = 4; + let family_id = cx.font_cache().load_family(&["Helvetica"]).unwrap(); + let font_id = cx + .font_cache() + .select_font(family_id, &Default::default()) + .unwrap(); + let font_size = 14.0; + + let buffer = MultiBuffer::build_simple(&text, cx); + let display_map = cx + .add_model(|cx| DisplayMap::new(buffer, tab_size, font_id, font_size, None, 1, 1, cx)); + let snapshot = display_map.update(cx, |map, cx| map.snapshot(cx)); + let marked_display_points = marked_offsets + .into_iter() + .map(|offset| offset.to_display_point(&snapshot)) + .collect(); + + (snapshot, marked_display_points) + } + #[gpui::test] fn test_prev_next_word_boundary_multibyte(cx: &mut gpui::MutableAppContext) { let tab_size = 4; @@ -312,44 +390,44 @@ mod tests { .add_model(|cx| DisplayMap::new(buffer, tab_size, font_id, font_size, None, 1, 1, cx)); let snapshot = display_map.update(cx, |map, cx| map.snapshot(cx)); assert_eq!( - prev_word_boundary(&snapshot, DisplayPoint::new(0, 12)), + previous_word_start(&snapshot, DisplayPoint::new(0, 12)), DisplayPoint::new(0, 7) ); assert_eq!( - prev_word_boundary(&snapshot, DisplayPoint::new(0, 7)), + previous_word_start(&snapshot, DisplayPoint::new(0, 7)), DisplayPoint::new(0, 2) ); assert_eq!( - prev_word_boundary(&snapshot, DisplayPoint::new(0, 6)), + previous_word_start(&snapshot, DisplayPoint::new(0, 6)), DisplayPoint::new(0, 2) ); assert_eq!( - prev_word_boundary(&snapshot, DisplayPoint::new(0, 2)), + previous_word_start(&snapshot, DisplayPoint::new(0, 2)), DisplayPoint::new(0, 0) ); assert_eq!( - prev_word_boundary(&snapshot, DisplayPoint::new(0, 1)), + previous_word_start(&snapshot, DisplayPoint::new(0, 1)), DisplayPoint::new(0, 0) ); assert_eq!( - next_word_boundary(&snapshot, DisplayPoint::new(0, 0)), + next_word_end(&snapshot, DisplayPoint::new(0, 0)), DisplayPoint::new(0, 1) ); assert_eq!( - next_word_boundary(&snapshot, DisplayPoint::new(0, 1)), + next_word_end(&snapshot, DisplayPoint::new(0, 1)), DisplayPoint::new(0, 6) ); assert_eq!( - next_word_boundary(&snapshot, DisplayPoint::new(0, 2)), + next_word_end(&snapshot, DisplayPoint::new(0, 2)), DisplayPoint::new(0, 6) ); assert_eq!( - next_word_boundary(&snapshot, DisplayPoint::new(0, 6)), + next_word_end(&snapshot, DisplayPoint::new(0, 6)), DisplayPoint::new(0, 12) ); assert_eq!( - next_word_boundary(&snapshot, DisplayPoint::new(0, 7)), + next_word_end(&snapshot, DisplayPoint::new(0, 7)), DisplayPoint::new(0, 12) ); }