diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 288d25f9cd22e6245d3d743db8ddff1d1433a335..55c31cfa8074734343dd62bb6e138129d77b0d9b 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -6467,40 +6467,77 @@ impl Editor { } self.select_next_state = Some(select_next_state); - } else if selections.len() == 1 { - let selection = selections.last_mut().unwrap(); - if selection.start == selection.end { - let word_range = movement::surrounding_word( - &display_map, - selection.start.to_display_point(&display_map), - ); - selection.start = word_range.start.to_offset(&display_map, Bias::Left); - selection.end = word_range.end.to_offset(&display_map, Bias::Left); - selection.goal = SelectionGoal::None; - selection.reversed = false; + } else { + let mut only_carets = true; + let mut same_letters_selected = true; + let mut selection_query = None; + + let mut selections_iter = selections.iter().peekable(); + while let Some(selection) = selections_iter.next() { + if selection.start != selection.end { + only_carets = false; + } - let query = buffer - .text_for_range(selection.start..selection.end) - .collect::(); + if same_letters_selected { + if selection_query.is_none() { + selection_query = + Some(buffer.text_for_range(selection.range()).collect::()); + } - let is_empty = query.is_empty(); - let select_state = SelectNextState { - query: AhoCorasick::new(&[query])?, - wordwise: true, - done: is_empty, - }; - select_next_match_ranges( - self, - selection.start..selection.end, - replace_newest, - autoscroll, - cx, - ); - self.select_next_state = Some(select_state); - } else { - let query = buffer - .text_for_range(selection.start..selection.end) - .collect::(); + if let Some(next_selection) = selections_iter.peek() { + if next_selection.range().len() == selection.range().len() { + let next_query = buffer + .text_for_range(next_selection.range()) + .collect::(); + if Some(next_query) != selection_query { + same_letters_selected = false; + selection_query = None; + } + } else { + same_letters_selected = false; + selection_query = None; + } + } + } + } + + if only_carets { + for selection in &mut selections { + let word_range = movement::surrounding_word( + &display_map, + selection.start.to_display_point(&display_map), + ); + selection.start = word_range.start.to_offset(&display_map, Bias::Left); + selection.end = word_range.end.to_offset(&display_map, Bias::Left); + selection.goal = SelectionGoal::None; + selection.reversed = false; + select_next_match_ranges( + self, + selection.start..selection.end, + replace_newest, + autoscroll, + cx, + ); + } + + if selections.len() == 1 { + let selection = selections + .last() + .expect("ensured that there's only one selection"); + let query = buffer + .text_for_range(selection.start..selection.end) + .collect::(); + let is_empty = query.is_empty(); + let select_state = SelectNextState { + query: AhoCorasick::new(&[query])?, + wordwise: true, + done: is_empty, + }; + self.select_next_state = Some(select_state); + } else { + self.select_next_state = None; + } + } else if let Some(query) = selection_query { self.select_next_state = Some(SelectNextState { query: AhoCorasick::new(&[query])?, wordwise: false, @@ -6548,6 +6585,7 @@ impl Editor { Ok(()) } + // TODO kb test both select_next and select_previous pub fn select_previous( &mut self, action: &SelectPrevious, @@ -6606,37 +6644,79 @@ impl Editor { } self.select_prev_state = Some(select_prev_state); - } else if selections.len() == 1 { - let selection = selections.last_mut().unwrap(); - if selection.start == selection.end { - let word_range = movement::surrounding_word( - &display_map, - selection.start.to_display_point(&display_map), + } else { + let mut only_carets = true; + let mut same_letters_selected = true; + let mut selection_query = None; + + let mut selections_iter = selections.iter().peekable(); + while let Some(selection) = selections_iter.next() { + if selection.start != selection.end { + only_carets = false; + } + + if same_letters_selected { + if selection_query.is_none() { + selection_query = + Some(buffer.text_for_range(selection.range()).collect::()); + } + + if let Some(next_selection) = selections_iter.peek() { + if next_selection.range().len() == selection.range().len() { + let next_query = buffer + .text_for_range(next_selection.range()) + .collect::(); + if Some(next_query) != selection_query { + same_letters_selected = false; + selection_query = None; + } + } else { + same_letters_selected = false; + selection_query = None; + } + } + } + } + + if only_carets { + for selection in &mut selections { + let word_range = movement::surrounding_word( + &display_map, + selection.start.to_display_point(&display_map), + ); + selection.start = word_range.start.to_offset(&display_map, Bias::Left); + selection.end = word_range.end.to_offset(&display_map, Bias::Left); + selection.goal = SelectionGoal::None; + selection.reversed = false; + } + if selections.len() == 1 { + let selection = selections + .last() + .expect("ensured that there's only one selection"); + let query = buffer + .text_for_range(selection.start..selection.end) + .collect::(); + let is_empty = query.is_empty(); + let select_state = SelectNextState { + query: AhoCorasick::new(&[query])?, + wordwise: true, + done: is_empty, + }; + self.select_prev_state = Some(select_state); + } else { + self.select_prev_state = None; + } + + self.unfold_ranges( + selections.iter().map(|s| s.range()).collect::>(), + false, + true, + cx, ); - selection.start = word_range.start.to_offset(&display_map, Bias::Left); - selection.end = word_range.end.to_offset(&display_map, Bias::Left); - selection.goal = SelectionGoal::None; - selection.reversed = false; - - let query = buffer - .text_for_range(selection.start..selection.end) - .collect::(); - let query = query.chars().rev().collect::(); - let select_state = SelectNextState { - query: AhoCorasick::new(&[query])?, - wordwise: true, - done: false, - }; - self.unfold_ranges([selection.start..selection.end], false, true, cx); self.change_selections(Some(Autoscroll::newest()), cx, |s| { s.select(selections); }); - self.select_prev_state = Some(select_state); - } else { - let query = buffer - .text_for_range(selection.start..selection.end) - .collect::(); - let query = query.chars().rev().collect::(); + } else if let Some(query) = selection_query { self.select_prev_state = Some(SelectNextState { query: AhoCorasick::new(&[query])?, wordwise: false, diff --git a/crates/editor/src/scroll/autoscroll.rs b/crates/editor/src/scroll/autoscroll.rs index ba70739942c429e6b5eb11139a395b98db38475a..2a5ac568b79bb9df45489bf5e6b37f37ffcba25b 100644 --- a/crates/editor/src/scroll/autoscroll.rs +++ b/crates/editor/src/scroll/autoscroll.rs @@ -5,7 +5,7 @@ use language::Point; use crate::{display_map::ToDisplayPoint, Editor, EditorMode, LineWithInvisibles}; -#[derive(PartialEq, Eq)] +#[derive(PartialEq, Eq, Clone, Copy)] pub enum Autoscroll { Next, Strategy(AutoscrollStrategy), @@ -25,7 +25,7 @@ impl Autoscroll { } } -#[derive(PartialEq, Eq, Default)] +#[derive(PartialEq, Eq, Default, Clone, Copy)] pub enum AutoscrollStrategy { Fit, Newest,