diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 2bee666ef2..56e541603a 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -48,7 +48,7 @@ use std::{ cmp::{self, Ordering, Reverse}, iter::{self, FromIterator}, mem, - ops::{Deref, Range, RangeInclusive, Sub}, + ops::{Deref, DerefMut, Range, RangeInclusive, Sub}, sync::Arc, time::{Duration, Instant}, }; @@ -312,6 +312,10 @@ trait SelectionExt { -> Range; } +trait InvalidationRegion { + fn ranges(&self) -> &[Range]; +} + #[derive(Clone, Debug)] pub enum SelectPhase { Begin { @@ -385,7 +389,8 @@ pub struct Editor { select_next_state: Option, selection_history: HashMap]>, Option]>>)>, - action_region_stack: Vec, + autoclose_stack: InvalidationStack, + snippet_stack: InvalidationStack, select_larger_syntax_node_stack: Vec]>>, active_diagnostics: Option, scroll_position: Vector2F, @@ -431,30 +436,18 @@ struct SelectNextState { done: bool, } -#[derive(Debug)] -enum ActionRegionState { - BracketPair { - ranges: Vec>, - pair: BracketPair, - }, - Snippet { - ranges: Vec>>, - active_index: usize, - }, +struct BracketPairState { + ranges: Vec>, + pair: BracketPair, } -impl ActionRegionState { - fn ranges(&self) -> &[Range] { - match self { - ActionRegionState::BracketPair { ranges, .. } => ranges.as_slice(), - ActionRegionState::Snippet { - ranges, - active_index, - } => ranges[*active_index].as_slice(), - } - } +struct SnippetState { + ranges: Vec>>, + active_index: usize, } +struct InvalidationStack(Vec); + struct CompletionState { initial_position: Anchor, completions: Arc<[Completion]>, @@ -597,7 +590,8 @@ impl Editor { add_selections_state: None, select_next_state: None, selection_history: Default::default(), - action_region_stack: Vec::new(), + autoclose_stack: Default::default(), + snippet_stack: Default::default(), select_larger_syntax_node_stack: Vec::new(), active_diagnostics: None, build_settings, @@ -1528,7 +1522,7 @@ impl Editor { if pair.end.len() == 1 { let mut delta = 0; - bracket_pair_state = Some(ActionRegionState::BracketPair { + bracket_pair_state = Some(BracketPairState { ranges: selections .iter() .map(move |selection| { @@ -1547,33 +1541,27 @@ impl Editor { self.update_selections(new_selections, None, cx); } if let Some(bracket_pair_state) = bracket_pair_state { - self.action_region_stack.push(bracket_pair_state); + self.autoclose_stack.push(bracket_pair_state); } } fn skip_autoclose_end(&mut self, text: &str, cx: &mut ViewContext) -> bool { let old_selections = self.local_selections::(cx); - let mut autoclose_ranges = None; - if let Some(region_state) = self.action_region_stack.last() { - if let ActionRegionState::BracketPair { ranges, pair } = region_state { - if pair.end == text { - autoclose_ranges = Some(ranges.as_slice()); - } - } - } - - let autoclose_ranges = if let Some(ranges) = autoclose_ranges { - ranges + let autoclose_pair = if let Some(autoclose_pair) = self.autoclose_stack.last() { + autoclose_pair } else { return false; }; + if text != autoclose_pair.pair.end { + return false; + } - debug_assert_eq!(old_selections.len(), autoclose_ranges.len()); + debug_assert_eq!(old_selections.len(), autoclose_pair.ranges.len()); let buffer = self.buffer.read(cx).snapshot(cx); if old_selections .iter() - .zip(autoclose_ranges.iter().map(|r| r.to_offset(&buffer))) + .zip(autoclose_pair.ranges.iter().map(|r| r.to_offset(&buffer))) .all(|(selection, autoclose_range)| { let autoclose_range_end = autoclose_range.end.to_offset(&buffer); selection.is_empty() && selection.start == autoclose_range_end @@ -1592,7 +1580,7 @@ impl Editor { } }) .collect(); - self.action_region_stack.pop(); + self.autoclose_stack.pop(); self.update_selections(new_selections, Some(Autoscroll::Fit), cx); true } else { @@ -1790,7 +1778,7 @@ impl Editor { if let Some(tabstop) = tabstops.first() { self.select_ranges(tabstop.iter().cloned(), Some(Autoscroll::Fit), cx); - self.action_region_stack.push(ActionRegionState::Snippet { + self.snippet_stack.push(SnippetState { active_index: 0, ranges: tabstops, }); @@ -1811,61 +1799,48 @@ impl Editor { let buffer = self.buffer.read(cx).snapshot(cx); let old_selections = self.local_selections::(cx); - for (ix, region_state) in self.action_region_stack.iter().enumerate().rev() { - if let ActionRegionState::Snippet { .. } = region_state { - self.action_region_stack.truncate(ix + 1); - break; - } - } - - if let Some(region_state) = self.action_region_stack.last_mut() { - if let ActionRegionState::Snippet { - ranges, - active_index, - } = region_state - { - match bias { - Bias::Left => { - if *active_index > 0 { - *active_index -= 1; - } else { - return false; - } - } - Bias::Right => { - if *active_index + 1 < ranges.len() { - *active_index += 1; - } else { - return false; - } + if let Some(snippet) = self.snippet_stack.last_mut() { + match bias { + Bias::Left => { + if snippet.active_index > 0 { + snippet.active_index -= 1; + } else { + return false; } } - if let Some(current_ranges) = ranges.get(*active_index) { - let new_selections = old_selections - .into_iter() - .zip(current_ranges.iter()) - .map(|(selection, new_range)| { - let new_range = new_range.to_offset(&buffer); - Selection { - id: selection.id, - start: new_range.start, - end: new_range.end, - reversed: false, - goal: SelectionGoal::None, - } - }) - .collect(); - - // Remove the snippet state when moving to the last tabstop. - if *active_index + 1 == ranges.len() { - self.action_region_stack.pop(); + Bias::Right => { + if snippet.active_index + 1 < snippet.ranges.len() { + snippet.active_index += 1; + } else { + return false; } - - self.update_selections(new_selections, Some(Autoscroll::Fit), cx); - return true; } - self.action_region_stack.pop(); } + if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) { + let new_selections = old_selections + .into_iter() + .zip(current_ranges.iter()) + .map(|(selection, new_range)| { + let new_range = new_range.to_offset(&buffer); + Selection { + id: selection.id, + start: new_range.start, + end: new_range.end, + reversed: false, + goal: SelectionGoal::None, + } + }) + .collect(); + + // Remove the snippet state when moving to the last tabstop. + if snippet.active_index + 1 == snippet.ranges.len() { + self.snippet_stack.pop(); + } + + self.update_selections(new_selections, Some(Autoscroll::Fit), cx); + return true; + } + self.snippet_stack.pop(); } false @@ -3811,26 +3786,8 @@ impl Editor { self.add_selections_state = None; self.select_next_state = None; self.select_larger_syntax_node_stack.clear(); - while let Some(region_state) = self.action_region_stack.last() { - let region_ranges = region_state.ranges(); - let all_selections_inside_action_ranges = if selections.len() == region_ranges.len() { - selections - .iter() - .zip(region_ranges.iter().map(|r| r.to_point(&buffer))) - .all(|(selection, action_range)| { - let head = selection.head().to_point(&buffer); - action_range.start <= head && action_range.end >= head - }) - } else { - false - }; - - if all_selections_inside_action_ranges { - break; - } else { - self.action_region_stack.pop(); - } - } + self.autoclose_stack.invalidate(&selections, &buffer); + self.snippet_stack.invalidate(&selections, &buffer); let new_cursor_position = selections.iter().max_by_key(|s| s.id).map(|s| s.head()); if let Some(old_cursor_position) = old_cursor_position { @@ -4560,6 +4517,66 @@ impl SelectionExt for Selection { } } +impl InvalidationStack { + fn invalidate(&mut self, selections: &[Selection], buffer: &MultiBufferSnapshot) + where + S: Clone + ToOffset, + { + while let Some(region) = self.last() { + let all_selections_inside_invalidation_ranges = + if selections.len() == region.ranges().len() { + selections + .iter() + .zip(region.ranges().iter().map(|r| r.to_offset(&buffer))) + .all(|(selection, invalidation_range)| { + let head = selection.head().to_offset(&buffer); + invalidation_range.start <= head && invalidation_range.end >= head + }) + } else { + false + }; + + if all_selections_inside_invalidation_ranges { + break; + } else { + self.pop(); + } + } + } +} + +impl Default for InvalidationStack { + fn default() -> Self { + Self(Default::default()) + } +} + +impl Deref for InvalidationStack { + type Target = Vec; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for InvalidationStack { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl InvalidationRegion for BracketPairState { + fn ranges(&self) -> &[Range] { + &self.ranges + } +} + +impl InvalidationRegion for SnippetState { + fn ranges(&self) -> &[Range] { + &self.ranges[self.active_index] + } +} + pub fn diagnostic_block_renderer( diagnostic: Diagnostic, is_valid: bool,