From 8432daef6a02a0c2d8f33dd33ca6c8b7a3d1e270 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Fri, 10 Dec 2021 19:23:34 -0700 Subject: [PATCH] WIP: Start on removing selections from buffer in favor of editor --- crates/editor/src/editor.rs | 309 ++++++++++++++-------------- crates/editor/src/element.rs | 51 ++--- crates/editor/src/items.rs | 4 +- crates/editor/src/multi_buffer.rs | 187 ++--------------- crates/language/src/buffer.rs | 169 ++------------- crates/language/src/tests.rs | 109 +++++----- crates/project/src/worktree.rs | 59 +++--- crates/server/src/rpc.rs | 20 +- crates/text/src/tests.rs | 58 ++---- crates/text/src/text.rs | 327 ++---------------------------- 10 files changed, 342 insertions(+), 951 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index ac112a25c8..c82a5d6d2f 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -23,11 +23,11 @@ use gpui::{ use items::BufferItemHandle; use language::{ BracketPair, Buffer, Diagnostic, DiagnosticSeverity, Language, Point, Selection, SelectionGoal, - SelectionSetId, + SelectionSetId, TransactionId, }; pub use multi_buffer::MultiBuffer; use multi_buffer::{ - Anchor, AnchorRangeExt, MultiBufferChunks, MultiBufferSnapshot, SelectionSet, ToOffset, ToPoint, + Anchor, AnchorRangeExt, MultiBufferChunks, MultiBufferSnapshot, ToOffset, ToPoint, }; use serde::{Deserialize, Serialize}; use smallvec::SmallVec; @@ -36,7 +36,8 @@ use std::{ cell::RefCell, cmp, collections::HashMap, - iter, mem, + iter::{self, FromIterator}, + mem, ops::{Deref, Range, RangeInclusive, Sub}, rc::Rc, sync::Arc, @@ -359,12 +360,14 @@ pub struct Editor { handle: WeakViewHandle, buffer: ModelHandle, display_map: ModelHandle, - selection_set_id: SelectionSetId, + next_selection_id: usize, + selections: Arc<[Selection]>, pending_selection: Option, columnar_selection_tail: Option, - next_selection_id: usize, add_selections_state: Option, select_next_state: Option, + selection_history: + HashMap]>, Option]>>)>, autoclose_stack: Vec, select_larger_syntax_node_stack: Vec]>>, active_diagnostics: Option, @@ -487,28 +490,27 @@ impl Editor { .detach(); let mut next_selection_id = 0; - let selection_set_id = buffer.update(cx, |buffer, cx| { - buffer.add_selection_set( - &[Selection { - id: post_inc(&mut next_selection_id), - start: 0, - end: 0, - reversed: false, - goal: SelectionGoal::None, - }], - cx, - ) - }); + let selections = Arc::from( + &[Selection { + id: post_inc(&mut next_selection_id), + start: Anchor::min(), + end: Anchor::min(), + reversed: false, + goal: SelectionGoal::None, + }][..], + ); + Self { handle: cx.weak_handle(), buffer, display_map, - selection_set_id, + selections, pending_selection: None, columnar_selection_tail: None, next_selection_id, add_selections_state: None, select_next_state: None, + selection_history: Default::default(), autoclose_stack: Default::default(), select_larger_syntax_node_stack: Vec::new(), active_diagnostics: None, @@ -636,7 +638,7 @@ impl Editor { let first_cursor_top; let last_cursor_bottom; if autoscroll == Autoscroll::Newest { - let newest_selection = self.newest_selection::(cx); + let newest_selection = self.newest_selection::(&display_map.buffer_snapshot, cx); first_cursor_top = newest_selection.head().to_display_point(&display_map).row() as f32; last_cursor_bottom = first_cursor_top + 1.; } else { @@ -769,7 +771,9 @@ impl Editor { cx: &mut ViewContext, ) { let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let tail = self.newest_selection::(cx).tail(); + let tail = self + .newest_selection::(&display_map.buffer_snapshot, cx) + .tail(); self.begin_selection(position, false, click_count, cx); let position = position.to_offset(&display_map, Bias::Left); @@ -851,7 +855,7 @@ impl Editor { self.update_selections::(Vec::new(), None, cx); } else if click_count > 1 { // Remove the newest selection since it was only added as part of this multi-click. - let newest_selection = self.newest_selection::(cx); + let newest_selection = self.newest_selection::(buffer, cx); let mut selections = self.selections(cx); selections.retain(|selection| selection.id != newest_selection.id); self.update_selections::(selections, None, cx) @@ -874,7 +878,9 @@ impl Editor { } let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let tail = self.newest_selection::(cx).tail(); + let tail = self + .newest_selection::(&display_map.buffer_snapshot, cx) + .tail(); self.columnar_selection_tail = Some(display_map.buffer_snapshot.anchor_before(tail)); self.select_columns( @@ -2812,7 +2818,7 @@ impl Editor { pub fn show_next_diagnostic(&mut self, _: &ShowNextDiagnostic, cx: &mut ViewContext) { let buffer = self.buffer.read(cx).snapshot(cx); - let selection = self.newest_selection::(cx); + let selection = self.newest_selection::(&buffer, cx); let active_primary_range = self.active_diagnostics.as_ref().map(|active_diagnostics| { active_diagnostics .primary_range @@ -2992,120 +2998,119 @@ impl Editor { } } - pub fn active_selection_sets<'a>( - &'a self, - cx: &'a AppContext, - ) -> impl 'a + Iterator { - let buffer = self.buffer.read(cx); - let replica_id = buffer.replica_id(); - buffer - .selection_sets(cx) - .filter(move |(set_id, set)| { - set.active && (set_id.replica_id != replica_id || **set_id == self.selection_set_id) - }) - .map(|(set_id, _)| *set_id) - } - pub fn intersecting_selections<'a>( &'a self, set_id: SelectionSetId, range: Range, cx: &'a mut MutableAppContext, ) -> Vec> { - let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); - let buffer = self.buffer.read(cx); + todo!() + // let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx)); + // let buffer = self.buffer.read(cx); - let pending_selection = if set_id == self.selection_set_id { - self.pending_selection.as_ref().and_then(|pending| { - let selection_start = pending.selection.start.to_display_point(&display_map); - let selection_end = pending.selection.end.to_display_point(&display_map); - if selection_start <= range.end || selection_end <= range.end { - Some(Selection { - id: pending.selection.id, - start: selection_start, - end: selection_end, - reversed: pending.selection.reversed, - goal: pending.selection.goal, - }) - } else { - None - } - }) - } else { - None - }; + // let pending_selection = if set_id == self.selection_set_id { + // self.pending_selection.as_ref().and_then(|pending| { + // let selection_start = pending.selection.start.to_display_point(&display_map); + // let selection_end = pending.selection.end.to_display_point(&display_map); + // if selection_start <= range.end || selection_end <= range.end { + // Some(Selection { + // id: pending.selection.id, + // start: selection_start, + // end: selection_end, + // reversed: pending.selection.reversed, + // goal: pending.selection.goal, + // }) + // } else { + // None + // } + // }) + // } else { + // None + // }; - let range = (range.start.to_offset(&display_map, Bias::Left), Bias::Left) - ..(range.end.to_offset(&display_map, Bias::Left), Bias::Right); - buffer - .selection_set(set_id, cx) - .unwrap() - .intersecting_selections::(range, &buffer.read(cx)) - .map(move |s| Selection { - id: s.id, - start: s.start.to_display_point(&display_map), - end: s.end.to_display_point(&display_map), - reversed: s.reversed, - goal: s.goal, - }) - .chain(pending_selection) - .collect() + // let range = (range.start.to_offset(&display_map, Bias::Left), Bias::Left) + // ..(range.end.to_offset(&display_map, Bias::Left), Bias::Right); + // buffer + // .selection_set(set_id, cx) + // .unwrap() + // .intersecting_selections::(range, &buffer.read(cx)) + // .map(move |s| Selection { + // id: s.id, + // start: s.start.to_display_point(&display_map), + // end: s.end.to_display_point(&display_map), + // reversed: s.reversed, + // goal: s.goal, + // }) + // .chain(pending_selection) + // .collect() } pub fn selections<'a, D>(&self, cx: &'a AppContext) -> Vec> where D: 'a + TextDimension + Ord + Sub, { - let buffer = self.buffer.read(cx).snapshot(cx); - let mut selections = self.selection_set(cx).selections::(&buffer).peekable(); - let mut pending_selection = self.pending_selection(cx); + // let buffer = self.buffer.read(cx).snapshot(cx); + // let mut selections = self.selection_set(cx).selections::(&buffer).peekable(); + // let mut pending_selection = self.pending_selection(cx); - iter::from_fn(move || { - if let Some(pending) = pending_selection.as_mut() { - while let Some(next_selection) = selections.peek() { - if pending.start <= next_selection.end && pending.end >= next_selection.start { - let next_selection = selections.next().unwrap(); - if next_selection.start < pending.start { - pending.start = next_selection.start; - } - if next_selection.end > pending.end { - pending.end = next_selection.end; - } - } else if next_selection.end < pending.start { - return selections.next(); - } else { - break; - } - } + // iter::from_fn(move || { + // if let Some(pending) = pending_selection.as_mut() { + // while let Some(next_selection) = selections.peek() { + // if pending.start <= next_selection.end && pending.end >= next_selection.start { + // let next_selection = selections.next().unwrap(); + // if next_selection.start < pending.start { + // pending.start = next_selection.start; + // } + // if next_selection.end > pending.end { + // pending.end = next_selection.end; + // } + // } else if next_selection.end < pending.start { + // return selections.next(); + // } else { + // break; + // } + // } - pending_selection.take() - } else { - selections.next() - } - }) - .collect() + // pending_selection.take() + // } else { + // selections.next() + // } + // }) + // .collect() + todo!() } fn pending_selection>( &self, + snapshot: &MultiBufferSnapshot, cx: &AppContext, ) -> Option> { - let buffer = self.buffer.read(cx).read(cx); - self.pending_selection.as_ref().map(|pending| Selection { - id: pending.selection.id, - start: pending.selection.start.summary::(&buffer), - end: pending.selection.end.summary::(&buffer), - reversed: pending.selection.reversed, - goal: pending.selection.goal, - }) + self.pending_selection + .as_ref() + .map(|pending| self.resolve_selection(&pending.selection, &snapshot, cx)) + } + + fn resolve_selection>( + &self, + selection: &Selection, + buffer: &MultiBufferSnapshot, + cx: &AppContext, + ) -> Selection { + Selection { + id: selection.id, + start: selection.start.summary::(&buffer), + end: selection.end.summary::(&buffer), + reversed: selection.reversed, + goal: selection.goal, + } } fn selection_count<'a>(&self, cx: &'a AppContext) -> usize { - let mut selection_count = self.selection_set(cx).len(); + let mut count = self.selections.len(); if self.pending_selection.is_some() { - selection_count += 1; + count += 1; } - selection_count + count } pub fn oldest_selection>( @@ -3113,31 +3118,29 @@ impl Editor { snapshot: &MultiBufferSnapshot, cx: &AppContext, ) -> Selection { - self.selection_set(cx) - .oldest_selection(snapshot) - .or_else(|| self.pending_selection(cx)) + self.selections + .iter() + .min_by_key(|s| s.id) + .map(|selection| self.resolve_selection(selection, snapshot, cx)) + .or_else(|| self.pending_selection(snapshot, cx)) .unwrap() } pub fn newest_selection>( &self, + snapshot: &MultiBufferSnapshot, cx: &AppContext, ) -> Selection { - self.pending_selection(cx) + self.pending_selection(snapshot, cx) .or_else(|| { - self.selection_set(cx) - .newest_selection(&self.buffer.read(cx).read(cx)) + self.selections + .iter() + .min_by_key(|s| s.id) + .map(|selection| self.resolve_selection(selection, snapshot, cx)) }) .unwrap() } - fn selection_set<'a>(&self, cx: &'a AppContext) -> &'a SelectionSet { - self.buffer - .read(cx) - .selection_set(self.selection_set_id, cx) - .unwrap() - } - pub fn update_selections( &mut self, mut selections: Vec>, @@ -3193,11 +3196,13 @@ impl Editor { } self.pause_cursor_blinking(cx); - self.buffer.update(cx, |buffer, cx| { - buffer - .update_selection_set(self.selection_set_id, &selections, cx) - .unwrap(); - }); + self.selections = Arc::from_iter(selections.into_iter().map(|selection| Selection { + id: selection.id, + start: buffer.anchor_before(selection.start), + end: buffer.anchor_before(selection.end), + reversed: selection.reversed, + goal: selection.goal, + })); } fn request_autoscroll(&mut self, autoscroll: Autoscroll, cx: &mut ViewContext) { @@ -3208,13 +3213,13 @@ impl Editor { fn start_transaction(&mut self, cx: &mut ViewContext) { self.end_selection(cx); self.buffer.update(cx, |buffer, cx| { - buffer.start_transaction([self.selection_set_id], cx); + buffer.start_transaction(cx); }); } fn end_transaction(&self, cx: &mut ViewContext) { self.buffer.update(cx, |buffer, cx| { - buffer.end_transaction([self.selection_set_id], cx); + buffer.end_transaction(cx); }); } @@ -3549,14 +3554,6 @@ pub enum Event { impl Entity for Editor { type Event = Event; - - fn release(&mut self, cx: &mut MutableAppContext) { - self.buffer.update(cx, |buffer, cx| { - buffer - .remove_selection_set(self.selection_set_id, cx) - .unwrap(); - }); - } } impl View for Editor { @@ -3579,19 +3576,11 @@ impl View for Editor { fn on_focus(&mut self, cx: &mut ViewContext) { self.focused = true; self.blink_cursors(self.blink_epoch, cx); - self.buffer.update(cx, |buffer, cx| { - buffer - .set_active_selection_set(Some(self.selection_set_id), cx) - .unwrap(); - }); } fn on_blur(&mut self, cx: &mut ViewContext) { self.focused = false; self.show_local_cursors = false; - self.buffer.update(cx, |buffer, cx| { - buffer.set_active_selection_set(None, cx).unwrap(); - }); cx.emit(Event::Blurred); cx.notify(); } @@ -3710,6 +3699,8 @@ pub fn diagnostic_style( #[cfg(test)] mod tests { + use std::mem; + use super::*; use language::LanguageConfig; use text::Point; @@ -5670,20 +5661,18 @@ mod tests { impl Editor { fn selection_ranges(&self, cx: &mut MutableAppContext) -> Vec> { - self.intersecting_selections( - self.selection_set_id, - DisplayPoint::zero()..self.max_point(cx), - cx, - ) - .into_iter() - .map(|s| { - if s.reversed { - s.end..s.start - } else { - s.start..s.end - } - }) - .collect() + let snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx)); + self.selections + .iter() + .map(|s| { + let mut range = + s.start.to_display_point(&snapshot)..s.end.to_display_point(&snapshot); + if s.reversed { + mem::swap(&mut range.start, &mut range.end); + } + range + }) + .collect() } } diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 89c324a1ec..27b29e678c 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -733,34 +733,37 @@ impl Element for EditorElement { let scroll_top = scroll_position.y() * line_height; let end_row = ((scroll_top + size.y()) / line_height).ceil() as u32 + 1; // Add 1 to ensure selections bleed off screen - let mut selections = HashMap::new(); - let mut active_rows = BTreeMap::new(); + let selections = HashMap::new(); + let active_rows = BTreeMap::new(); let mut highlighted_row = None; self.update_view(cx.app, |view, cx| { highlighted_row = view.highlighted_row(); - for selection_set_id in view.active_selection_sets(cx).collect::>() { - let replica_selections = view.intersecting_selections( - selection_set_id, - DisplayPoint::new(start_row, 0)..DisplayPoint::new(end_row, 0), - cx, - ); - for selection in &replica_selections { - if selection_set_id == view.selection_set_id { - let is_empty = selection.start == selection.end; - let selection_start = snapshot.prev_row_boundary(selection.start).0; - let selection_end = snapshot.next_row_boundary(selection.end).0; - for row in cmp::max(selection_start.row(), start_row) - ..=cmp::min(selection_end.row(), end_row) - { - let contains_non_empty_selection = - active_rows.entry(row).or_insert(!is_empty); - *contains_non_empty_selection |= !is_empty; - } - } - } - selections.insert(selection_set_id.replica_id, replica_selections); - } + // TODO: Get this working with editors owning their own selections + + // for selection_set_id in view.active_selection_sets(cx).collect::>() { + // let replica_selections = view.intersecting_selections( + // selection_set_id, + // DisplayPoint::new(start_row, 0)..DisplayPoint::new(end_row, 0), + // cx, + // ); + // for selection in &replica_selections { + // if selection_set_id == view.selection_set_id { + // let is_empty = selection.start == selection.end; + // let selection_start = snapshot.prev_row_boundary(selection.start).0; + // let selection_end = snapshot.next_row_boundary(selection.end).0; + // for row in cmp::max(selection_start.row(), start_row) + // ..=cmp::min(selection_end.row(), end_row) + // { + // let contains_non_empty_selection = + // active_rows.entry(row).or_insert(!is_empty); + // *contains_non_empty_selection |= !is_empty; + // } + // } + // } + + // selections.insert(selection_set_id.replica_id, replica_selections); + // } }); let line_number_layouts = self.layout_rows(start_row..end_row, &active_rows, &snapshot, cx); diff --git a/crates/editor/src/items.rs b/crates/editor/src/items.rs index 2ecfac3646..cbc9ff223d 100644 --- a/crates/editor/src/items.rs +++ b/crates/editor/src/items.rs @@ -322,8 +322,10 @@ impl DiagnosticMessage { fn update(&mut self, editor: ViewHandle, cx: &mut ViewContext) { let editor = editor.read(cx); - let cursor_position = editor.newest_selection::(cx).head(); let buffer = editor.buffer().read(cx); + let cursor_position = editor + .newest_selection::(&buffer.read(cx), cx) + .head(); let new_diagnostic = buffer .read(cx) .diagnostics_in_range::<_, usize>(cursor_position..cursor_position) diff --git a/crates/editor/src/multi_buffer.rs b/crates/editor/src/multi_buffer.rs index 8163a7bd23..5f2ca98f8d 100644 --- a/crates/editor/src/multi_buffer.rs +++ b/crates/editor/src/multi_buffer.rs @@ -24,7 +24,7 @@ use text::{ locator::Locator, rope::TextDimension, subscription::{Subscription, Topic}, - AnchorRangeExt as _, Edit, Point, PointUtf16, Selection, SelectionSetId, TextSummary, + AnchorRangeExt as _, Edit, Point, PointUtf16, SelectionSetId, TextSummary, }; use theme::SyntaxTheme; @@ -113,7 +113,7 @@ impl MultiBuffer { pub fn singleton(buffer: ModelHandle, cx: &mut ModelContext) -> Self { let mut this = Self::new(buffer.read(cx).replica_id()); this.singleton = true; - this.push( + this.push_excerpt( ExcerptProperties { buffer: &buffer, range: text::Anchor::min()..text::Anchor::max(), @@ -202,26 +202,18 @@ impl MultiBuffer { }); } - pub fn start_transaction( - &mut self, - selection_set_ids: impl IntoIterator, - cx: &mut ModelContext, - ) -> Option { + pub fn start_transaction(&mut self, cx: &mut ModelContext) -> Option { // TODO self.as_singleton() .unwrap() - .update(cx, |buffer, _| buffer.start_transaction(selection_set_ids)) + .update(cx, |buffer, _| buffer.start_transaction()) } - pub fn end_transaction( - &mut self, - selection_set_ids: impl IntoIterator, - cx: &mut ModelContext, - ) -> Option { + pub fn end_transaction(&mut self, cx: &mut ModelContext) -> Option { // TODO - self.as_singleton().unwrap().update(cx, |buffer, cx| { - buffer.end_transaction(selection_set_ids, cx) - }) + self.as_singleton() + .unwrap() + .update(cx, |buffer, cx| buffer.end_transaction(cx)) } pub fn undo(&mut self, cx: &mut ModelContext) -> Option { @@ -238,153 +230,11 @@ impl MultiBuffer { .update(cx, |buffer, cx| buffer.redo(cx)) } - pub fn selection_set(&self, set_id: SelectionSetId, cx: &AppContext) -> Result<&SelectionSet> { - // TODO - let set = self - .as_singleton() - .unwrap() - .read(cx) - .selection_set(set_id)?; - let excerpt_id = self.snapshot.borrow().excerpts.first().unwrap().id.clone(); - - let selection_sets: &mut HashMap = - unsafe { &mut *(&self.selection_sets as *const _ as *mut _) }; - selection_sets.insert( - set_id, - SelectionSet { - id: set.id, - active: set.active, - selections: set - .selections - .iter() - .map(|selection| Selection { - id: selection.id, - start: Anchor { - excerpt_id: excerpt_id.clone(), - text_anchor: selection.start.clone(), - }, - end: Anchor { - excerpt_id: excerpt_id.clone(), - text_anchor: selection.end.clone(), - }, - reversed: selection.reversed, - goal: selection.goal, - }) - .collect(), - }, - ); - Ok(self.selection_sets.get(&set.id).unwrap()) - } - - pub fn add_selection_set( + pub fn push_excerpt( &mut self, - selections: &[Selection], + props: ExcerptProperties, cx: &mut ModelContext, - ) -> SelectionSetId { - // TODO - let snapshot = self.read(cx); - self.as_singleton().unwrap().update(cx, |buffer, cx| { - buffer.add_selection_set( - &selections - .iter() - .map(|selection| Selection { - id: selection.id, - start: selection.start.to_offset(&snapshot), - end: selection.end.to_offset(&snapshot), - reversed: selection.reversed, - goal: selection.goal, - }) - .collect::>(), - cx, - ) - }) - } - - pub fn remove_selection_set( - &mut self, - set_id: SelectionSetId, - cx: &mut ModelContext, - ) -> Result<()> { - // TODO - self.as_singleton() - .unwrap() - .update(cx, |buffer, cx| buffer.remove_selection_set(set_id, cx)) - } - - pub fn update_selection_set( - &mut self, - set_id: SelectionSetId, - selections: &[Selection], - cx: &mut ModelContext, - ) -> Result<()> { - // TODO - let snapshot = self.read(cx); - self.as_singleton().unwrap().update(cx, |buffer, cx| { - buffer.update_selection_set( - set_id, - &selections - .iter() - .map(|selection| Selection { - id: selection.id, - start: selection.start.to_offset(&snapshot), - end: selection.end.to_offset(&snapshot), - reversed: selection.reversed, - goal: selection.goal, - }) - .collect::>(), - cx, - ) - }) - } - - pub fn set_active_selection_set( - &mut self, - set_id: Option, - cx: &mut ModelContext, - ) -> Result<()> { - self.as_singleton() - .unwrap() - .update(cx, |buffer, cx| buffer.set_active_selection_set(set_id, cx)) - } - - pub fn selection_sets( - &self, - cx: &AppContext, - ) -> impl Iterator { - let excerpt_id = self.snapshot.borrow().excerpts.first().unwrap().id.clone(); - let selection_sets: &mut HashMap = - unsafe { &mut *(&self.selection_sets as *const _ as *mut _) }; - selection_sets.clear(); - for (selection_set_id, set) in self.as_singleton().unwrap().read(cx).selection_sets() { - selection_sets.insert( - *selection_set_id, - SelectionSet { - id: set.id, - active: set.active, - selections: set - .selections - .iter() - .map(|selection| Selection { - id: selection.id, - start: Anchor { - excerpt_id: excerpt_id.clone(), - text_anchor: selection.start.clone(), - }, - end: Anchor { - excerpt_id: excerpt_id.clone(), - text_anchor: selection.end.clone(), - }, - reversed: selection.reversed, - goal: selection.goal, - }) - .collect(), - }, - ); - } - self.selection_sets.iter() - } - - pub fn push(&mut self, props: ExcerptProperties, cx: &mut ModelContext) -> ExcerptId + ) -> ExcerptId where O: text::ToOffset, { @@ -555,13 +405,6 @@ impl MultiBuffer { .update(cx, |buffer, cx| buffer.randomly_edit(rng, count, cx)); self.sync(cx); } - - pub fn randomly_mutate(&mut self, rng: &mut R, cx: &mut ModelContext) { - self.as_singleton() - .unwrap() - .update(cx, |buffer, cx| buffer.randomly_mutate(rng, cx)); - self.sync(cx); - } } impl Entity for MultiBuffer { @@ -1389,7 +1232,7 @@ mod tests { let subscription = multibuffer.update(cx, |multibuffer, cx| { let subscription = multibuffer.subscribe(); - multibuffer.push( + multibuffer.push_excerpt( ExcerptProperties { buffer: &buffer_1, range: Point::new(1, 2)..Point::new(2, 5), @@ -1405,7 +1248,7 @@ mod tests { }] ); - multibuffer.push( + multibuffer.push_excerpt( ExcerptProperties { buffer: &buffer_1, range: Point::new(3, 3)..Point::new(4, 4), @@ -1413,7 +1256,7 @@ mod tests { }, cx, ); - multibuffer.push( + multibuffer.push_excerpt( ExcerptProperties { buffer: &buffer_2, range: Point::new(3, 1)..Point::new(3, 3), @@ -1529,7 +1372,7 @@ mod tests { ); let excerpt_id = list.update(cx, |list, cx| { - list.push( + list.push_excerpt( ExcerptProperties { buffer: &buffer_handle, range: start_ix..end_ix, diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index 1830e49bf7..b408bf589b 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -178,7 +178,6 @@ struct SyntaxTree { #[derive(Clone)] struct AutoindentRequest { - selection_set_ids: HashSet, before_edit: BufferSnapshot, edited: Vec, inserted: Option>>, @@ -277,10 +276,6 @@ impl Buffer { .into_iter() .map(|op| text::Operation::Edit(proto::deserialize_edit_operation(op))); buffer.apply_ops(ops)?; - for set in message.selections { - let set = proto::deserialize_selection_set(set); - buffer.add_raw_selection_set(set.id, set); - } let mut this = Self::build(buffer, file); this.apply_diagnostic_update( Arc::from(proto::deserialize_diagnostics(message.diagnostics)), @@ -299,10 +294,7 @@ impl Buffer { .history() .map(proto::serialize_edit_operation) .collect(), - selections: self - .selection_sets() - .map(|(_, set)| proto::serialize_selection_set(set)) - .collect(), + selections: Vec::new(), diagnostics: proto::serialize_diagnostics(self.diagnostics.iter()), } } @@ -971,49 +963,11 @@ impl Buffer { indent_columns: BTreeMap, cx: &mut ModelContext, ) { - let selection_set_ids = self - .autoindent_requests - .drain(..) - .flat_map(|req| req.selection_set_ids.clone()) - .collect::>(); - - self.start_transaction(selection_set_ids.iter().copied()); + self.start_transaction(); for (row, indent_column) in &indent_columns { self.set_indent_column_for_line(*row, *indent_column, cx); } - - for selection_set_id in &selection_set_ids { - if let Ok(set) = self.selection_set(*selection_set_id) { - let new_selections = set - .selections::(&*self) - .map(|selection| { - if selection.start.column == 0 { - let delta = Point::new( - 0, - indent_columns - .get(&selection.start.row) - .copied() - .unwrap_or(0), - ); - if delta.column > 0 { - return Selection { - id: selection.id, - goal: selection.goal, - reversed: selection.reversed, - start: selection.start + delta, - end: selection.end + delta, - }; - } - } - selection - }) - .collect::>(); - self.update_selection_set(*selection_set_id, &new_selections, cx) - .unwrap(); - } - } - - self.end_transaction(selection_set_ids.iter().copied(), cx); + self.end_transaction(cx); } fn set_indent_column_for_line(&mut self, row: u32, column: u32, cx: &mut ModelContext) { @@ -1053,7 +1007,7 @@ impl Buffer { pub(crate) fn apply_diff(&mut self, diff: Diff, cx: &mut ModelContext) -> bool { if self.version == diff.base_version { - self.start_transaction(None); + self.start_transaction(); let mut offset = 0; for (tag, len) in diff.changes { let range = offset..(offset + len); @@ -1066,7 +1020,7 @@ impl Buffer { } } } - self.end_transaction(None, cx); + self.end_transaction(cx); true } else { false @@ -1090,38 +1044,24 @@ impl Buffer { self.text.subscribe() } - pub fn start_transaction( - &mut self, - selection_set_ids: impl IntoIterator, - ) -> Option { - self.start_transaction_at(selection_set_ids, Instant::now()) + pub fn start_transaction(&mut self) -> Option { + self.start_transaction_at(Instant::now()) } - pub(crate) fn start_transaction_at( - &mut self, - selection_set_ids: impl IntoIterator, - now: Instant, - ) -> Option { - self.text.start_transaction_at(selection_set_ids, now) + pub(crate) fn start_transaction_at(&mut self, now: Instant) -> Option { + self.text.start_transaction_at(now) } - pub fn end_transaction( - &mut self, - selection_set_ids: impl IntoIterator, - cx: &mut ModelContext, - ) -> Option { - self.end_transaction_at(selection_set_ids, Instant::now(), cx) + pub fn end_transaction(&mut self, cx: &mut ModelContext) -> Option { + self.end_transaction_at(Instant::now(), cx) } pub(crate) fn end_transaction_at( &mut self, - selection_set_ids: impl IntoIterator, now: Instant, cx: &mut ModelContext, ) -> Option { - if let Some((transaction_id, start_version)) = - self.text.end_transaction_at(selection_set_ids, now) - { + if let Some((transaction_id, start_version)) = self.text.end_transaction_at(now) { let was_dirty = start_version != self.saved_version; self.did_edit(&start_version, was_dirty, cx); Some(transaction_id) @@ -1212,7 +1152,7 @@ impl Buffer { return; } - self.start_transaction(None); + self.start_transaction(); self.pending_autoindent.take(); let autoindent_request = if autoindent && self.language.is_some() { let before_edit = self.snapshot(); @@ -1256,21 +1196,14 @@ impl Buffer { ); } - let selection_set_ids = self - .text - .peek_undo_stack() - .unwrap() - .starting_selection_set_ids() - .collect(); self.autoindent_requests.push(Arc::new(AutoindentRequest { - selection_set_ids, before_edit, edited, inserted, })); } - self.end_transaction(None, cx); + self.end_transaction(cx); self.send_operation(Operation::Buffer(text::Operation::Edit(edit)), cx); } @@ -1298,55 +1231,6 @@ impl Buffer { self.language.as_ref().and_then(|l| l.grammar.as_ref()) } - pub fn add_selection_set( - &mut self, - selections: &[Selection], - cx: &mut ModelContext, - ) -> SelectionSetId { - let operation = self.text.add_selection_set(selections); - if let text::Operation::UpdateSelections { set_id, .. } = &operation { - let set_id = *set_id; - cx.notify(); - self.send_operation(Operation::Buffer(operation), cx); - set_id - } else { - unreachable!() - } - } - - pub fn update_selection_set( - &mut self, - set_id: SelectionSetId, - selections: &[Selection], - cx: &mut ModelContext, - ) -> Result<()> { - let operation = self.text.update_selection_set(set_id, selections)?; - cx.notify(); - self.send_operation(Operation::Buffer(operation), cx); - Ok(()) - } - - pub fn set_active_selection_set( - &mut self, - set_id: Option, - cx: &mut ModelContext, - ) -> Result<()> { - let operation = self.text.set_active_selection_set(set_id)?; - self.send_operation(Operation::Buffer(operation), cx); - Ok(()) - } - - pub fn remove_selection_set( - &mut self, - set_id: SelectionSetId, - cx: &mut ModelContext, - ) -> Result<()> { - let operation = self.text.remove_selection_set(set_id)?; - cx.notify(); - self.send_operation(Operation::Buffer(operation), cx); - Ok(()) - } - pub fn apply_ops>( &mut self, ops: I, @@ -1447,10 +1331,8 @@ impl Buffer { let was_dirty = self.is_dirty(); let old_version = self.version.clone(); - if let Some((transaction_id, operations)) = self.text.undo() { - for operation in operations { - self.send_operation(Operation::Buffer(operation), cx); - } + if let Some((transaction_id, operation)) = self.text.undo() { + self.send_operation(Operation::Buffer(operation), cx); self.did_edit(&old_version, was_dirty, cx); Some(transaction_id) } else { @@ -1462,10 +1344,8 @@ impl Buffer { let was_dirty = self.is_dirty(); let old_version = self.version.clone(); - if let Some((transaction_id, operations)) = self.text.redo() { - for operation in operations { - self.send_operation(Operation::Buffer(operation), cx); - } + if let Some((transaction_id, operation)) = self.text.redo() { + self.send_operation(Operation::Buffer(operation), cx); self.did_edit(&old_version, was_dirty, cx); Some(transaction_id) } else { @@ -1484,18 +1364,9 @@ impl Buffer { ) where T: rand::Rng, { - self.start_transaction(None); + self.start_transaction(); self.text.randomly_edit(rng, old_range_count); - self.end_transaction(None, cx); - } - - pub fn randomly_mutate(&mut self, rng: &mut T, cx: &mut ModelContext) - where - T: rand::Rng, - { - self.start_transaction(None); - self.text.randomly_mutate(rng); - self.end_transaction(None, cx); + self.end_transaction(cx); } } diff --git a/crates/language/src/tests.rs b/crates/language/src/tests.rs index 686f088711..6e2bc43dcd 100644 --- a/crates/language/src/tests.rs +++ b/crates/language/src/tests.rs @@ -92,15 +92,15 @@ fn test_edit_events(cx: &mut gpui::MutableAppContext) { buffer.edit(Some(2..4), "XYZ", cx); // An empty transaction does not emit any events. - buffer.start_transaction(None); - buffer.end_transaction(None, cx); + buffer.start_transaction(); + buffer.end_transaction(cx); // A transaction containing two edits emits one edited event. now += Duration::from_secs(1); - buffer.start_transaction_at(None, now); + buffer.start_transaction_at(now); buffer.edit(Some(5..5), "u", cx); buffer.edit(Some(6..6), "w", cx); - buffer.end_transaction_at(None, now, cx); + buffer.end_transaction_at(now, cx); // Undoing a transaction emits one edited event. buffer.undo(cx); @@ -167,7 +167,7 @@ async fn test_reparse(mut cx: gpui::TestAppContext) { // Perform some edits (add parameter and variable reference) // Parsing doesn't begin until the transaction is complete buffer.update(&mut cx, |buf, cx| { - buf.start_transaction(None); + buf.start_transaction(); let offset = buf.text().find(")").unwrap(); buf.edit(vec![offset..offset], "b: C", cx); @@ -177,7 +177,7 @@ async fn test_reparse(mut cx: gpui::TestAppContext) { buf.edit(vec![offset..offset], " d; ", cx); assert!(!buf.is_parsing()); - buf.end_transaction(None, cx); + buf.end_transaction(cx); assert_eq!(buf.text(), "fn a(b: C) { d; }"); assert!(buf.is_parsing()); }); @@ -333,59 +333,62 @@ fn test_edit_with_autoindent(cx: &mut MutableAppContext) { }); } -#[gpui::test] -fn test_autoindent_moves_selections(cx: &mut MutableAppContext) { - cx.add_model(|cx| { - let text = "fn a() {}"; +// We need another approach to managing selections with auto-indent - let mut buffer = - Buffer::new(0, text, cx).with_language(Some(Arc::new(rust_lang())), None, cx); +// #[gpui::test] +// fn test_autoindent_moves_selections(cx: &mut MutableAppContext) { +// cx.add_model(|cx| { +// let text = "fn a() {}"; - let selection_set_id = buffer.add_selection_set::(&[], cx); - buffer.start_transaction(Some(selection_set_id)); - buffer.edit_with_autoindent([5..5, 9..9], "\n\n", cx); - buffer - .update_selection_set( - selection_set_id, - &[ - Selection { - id: 0, - start: Point::new(1, 0), - end: Point::new(1, 0), - reversed: false, - goal: SelectionGoal::None, - }, - Selection { - id: 1, - start: Point::new(4, 0), - end: Point::new(4, 0), - reversed: false, - goal: SelectionGoal::None, - }, - ], - cx, - ) - .unwrap(); - assert_eq!(buffer.text(), "fn a(\n\n) {}\n\n"); +// let mut buffer = +// Buffer::new(0, text, cx).with_language(Some(Arc::new(rust_lang())), None, cx); - // Ending the transaction runs the auto-indent. The selection - // at the start of the auto-indented row is pushed to the right. - buffer.end_transaction(Some(selection_set_id), cx); - assert_eq!(buffer.text(), "fn a(\n \n) {}\n\n"); - let selection_ranges = buffer - .selection_set(selection_set_id) - .unwrap() - .selections::(&buffer) - .map(|selection| selection.start.to_point(&buffer)..selection.end.to_point(&buffer)) - .collect::>(); +// let selection_set_id = buffer.add_selection_set::(&[], cx); +// buffer.start_transaction(); +// buffer.edit_with_autoindent([5..5, 9..9], "\n\n", cx); +// buffer +// .update_selection_set( +// selection_set_id, +// &[ +// Selection { +// id: 0, +// start: Point::new(1, 0), +// end: Point::new(1, 0), +// reversed: false, +// goal: SelectionGoal::None, +// }, +// Selection { +// id: 1, +// start: Point::new(4, 0), +// end: Point::new(4, 0), +// reversed: false, +// goal: SelectionGoal::None, +// }, +// ], +// cx, +// ) +// .unwrap(); +// assert_eq!(buffer.text(), "fn a(\n\n) {}\n\n"); - assert_eq!(selection_ranges[0], empty(Point::new(1, 4))); - assert_eq!(selection_ranges[1], empty(Point::new(4, 0))); +// // TODO! Come up with a different approach to moving selections now that we don't manage selection sets in the buffer - buffer - }); -} +// // Ending the transaction runs the auto-indent. The selection +// // at the start of the auto-indented row is pushed to the right. +// buffer.end_transaction(cx); +// assert_eq!(buffer.text(), "fn a(\n \n) {}\n\n"); +// let selection_ranges = buffer +// .selection_set(selection_set_id) +// .unwrap() +// .selections::(&buffer) +// .map(|selection| selection.start.to_point(&buffer)..selection.end.to_point(&buffer)) +// .collect::>(); +// assert_eq!(selection_ranges[0], empty(Point::new(1, 4))); +// assert_eq!(selection_ranges[1], empty(Point::new(4, 0))); + +// buffer +// }); +// } #[gpui::test] fn test_autoindent_does_not_adjust_lines_with_unchanged_suggestion(cx: &mut MutableAppContext) { cx.add_model(|cx| { diff --git a/crates/project/src/worktree.rs b/crates/project/src/worktree.rs index 020bf64b7f..fe6cb2e394 100644 --- a/crates/project/src/worktree.rs +++ b/crates/project/src/worktree.rs @@ -3559,7 +3559,6 @@ mod tests { #[gpui::test] async fn test_buffer_file_changes_on_disk(mut cx: gpui::TestAppContext) { use std::fs; - use text::{Point, Selection, SelectionGoal}; let initial_contents = "aaa\nbbbbb\nc\n"; let dir = temp_tree(json!({ "the-file": initial_contents })); @@ -3588,22 +3587,23 @@ mod tests { .await .unwrap(); + // TODO // Add a cursor on each row. - let selection_set_id = buffer.update(&mut cx, |buffer, cx| { - assert!(!buffer.is_dirty()); - buffer.add_selection_set( - &(0..3) - .map(|row| Selection { - id: row as usize, - start: Point::new(row, 1), - end: Point::new(row, 1), - reversed: false, - goal: SelectionGoal::None, - }) - .collect::>(), - cx, - ) - }); + // let selection_set_id = buffer.update(&mut cx, |buffer, cx| { + // assert!(!buffer.is_dirty()); + // buffer.add_selection_set( + // &(0..3) + // .map(|row| Selection { + // id: row as usize, + // start: Point::new(row, 1), + // end: Point::new(row, 1), + // reversed: false, + // goal: SelectionGoal::None, + // }) + // .collect::>(), + // cx, + // ) + // }); // Change the file on disk, adding two new lines of text, and removing // one line. @@ -3626,19 +3626,20 @@ mod tests { assert!(!buffer.is_dirty()); assert!(!buffer.has_conflict()); - let cursor_positions = buffer - .selection_set(selection_set_id) - .unwrap() - .selections::(&*buffer) - .map(|selection| { - assert_eq!(selection.start, selection.end); - selection.start - }) - .collect::>(); - assert_eq!( - cursor_positions, - [Point::new(1, 1), Point::new(3, 1), Point::new(4, 0)] - ); + // TODO + // let cursor_positions = buffer + // .selection_set(selection_set_id) + // .unwrap() + // .selections::(&*buffer) + // .map(|selection| { + // assert_eq!(selection.start, selection.end); + // selection.start + // }) + // .collect::>(); + // assert_eq!( + // cursor_positions, + // [Point::new(1, 1), Point::new(3, 1), Point::new(4, 0)] + // ); }); // Modify the buffer diff --git a/crates/server/src/rpc.rs b/crates/server/src/rpc.rs index 54f2432b21..7220740af4 100644 --- a/crates/server/src/rpc.rs +++ b/crates/server/src/rpc.rs @@ -1045,13 +1045,14 @@ mod tests { .await .unwrap(); - // Create a selection set as client B and see that selection set as client A. let editor_b = cx_b.add_view(window_b, |cx| { Editor::for_buffer(buffer_b, |cx| EditorSettings::test(cx), cx) }); - buffer_a - .condition(&cx_a, |buffer, _| buffer.selection_sets().count() == 1) - .await; + // TODO + // // Create a selection set as client B and see that selection set as client A. + // buffer_a + // .condition(&cx_a, |buffer, _| buffer.selection_sets().count() == 1) + // .await; // Edit the buffer as client B and see that edit as client A. editor_b.update(&mut cx_b, |editor, cx| { @@ -1061,11 +1062,12 @@ mod tests { .condition(&cx_a, |buffer, _| buffer.text() == "ok, b-contents") .await; - // Remove the selection set as client B, see those selections disappear as client A. - cx_b.update(move |_| drop(editor_b)); - buffer_a - .condition(&cx_a, |buffer, _| buffer.selection_sets().count() == 0) - .await; + // TODO + // // Remove the selection set as client B, see those selections disappear as client A. + // cx_b.update(move |_| drop(editor_b)); + // buffer_a + // .condition(&cx_a, |buffer, _| buffer.selection_sets().count() == 0) + // .await; // Close the buffer as client A, see that the buffer is closed. cx_a.update(move |_| drop(buffer_a)); diff --git a/crates/text/src/tests.rs b/crates/text/src/tests.rs index a470e8431e..94523de5a6 100644 --- a/crates/text/src/tests.rs +++ b/crates/text/src/tests.rs @@ -460,63 +460,41 @@ fn test_history() { let mut now = Instant::now(); let mut buffer = Buffer::new(0, 0, History::new("123456".into())); - let set_id = if let Operation::UpdateSelections { set_id, .. } = - buffer.add_selection_set(&buffer.selections_from_ranges(vec![4..4]).unwrap()) - { - set_id - } else { - unreachable!() - }; - buffer.start_transaction_at(Some(set_id), now); + buffer.start_transaction_at(now); buffer.edit(vec![2..4], "cd"); - buffer.end_transaction_at(Some(set_id), now); + buffer.end_transaction_at(now); assert_eq!(buffer.text(), "12cd56"); - assert_eq!(buffer.selection_ranges(set_id).unwrap(), vec![4..4]); - buffer.start_transaction_at(Some(set_id), now); - buffer - .update_selection_set(set_id, &buffer.selections_from_ranges(vec![1..3]).unwrap()) - .unwrap(); + buffer.start_transaction_at(now); buffer.edit(vec![4..5], "e"); - buffer.end_transaction_at(Some(set_id), now).unwrap(); + buffer.end_transaction_at(now).unwrap(); assert_eq!(buffer.text(), "12cde6"); - assert_eq!(buffer.selection_ranges(set_id).unwrap(), vec![1..3]); now += buffer.history.group_interval + Duration::from_millis(1); - buffer.start_transaction_at(Some(set_id), now); - buffer - .update_selection_set(set_id, &buffer.selections_from_ranges(vec![2..2]).unwrap()) - .unwrap(); + buffer.start_transaction_at(now); buffer.edit(vec![0..1], "a"); buffer.edit(vec![1..1], "b"); - buffer.end_transaction_at(Some(set_id), now).unwrap(); + buffer.end_transaction_at(now).unwrap(); assert_eq!(buffer.text(), "ab2cde6"); - assert_eq!(buffer.selection_ranges(set_id).unwrap(), vec![3..3]); - // Last transaction happened past the group interval, undo it on its - // own. + // Last transaction happened past the group interval, undo it on its own. buffer.undo(); assert_eq!(buffer.text(), "12cde6"); - assert_eq!(buffer.selection_ranges(set_id).unwrap(), vec![1..3]); - // First two transactions happened within the group interval, undo them - // together. + // First two transactions happened within the group interval, undo them together. buffer.undo(); assert_eq!(buffer.text(), "123456"); - assert_eq!(buffer.selection_ranges(set_id).unwrap(), vec![4..4]); // Redo the first two transactions together. buffer.redo(); assert_eq!(buffer.text(), "12cde6"); - assert_eq!(buffer.selection_ranges(set_id).unwrap(), vec![1..3]); // Redo the last transaction on its own. buffer.redo(); assert_eq!(buffer.text(), "ab2cde6"); - assert_eq!(buffer.selection_ranges(set_id).unwrap(), vec![3..3]); - buffer.start_transaction_at(None, now); - assert!(buffer.end_transaction_at(None, now).is_none()); + buffer.start_transaction_at(now); + assert!(buffer.end_transaction_at(now).is_none()); buffer.undo(); assert_eq!(buffer.text(), "12cde6"); } @@ -582,8 +560,8 @@ fn test_random_concurrent_edits(mut rng: StdRng) { let buffer = &mut buffers[replica_index]; match rng.gen_range(0..=100) { 0..=50 if mutation_count != 0 => { - let ops = buffer.randomly_mutate(&mut rng); - network.broadcast(buffer.replica_id, ops); + let op = buffer.randomly_edit(&mut rng, 5).2; + network.broadcast(buffer.replica_id, vec!(op)); log::info!("buffer {} text: {:?}", buffer.replica_id, buffer.text()); mutation_count -= 1; } @@ -620,18 +598,6 @@ fn test_random_concurrent_edits(mut rng: StdRng) { "Replica {} text != Replica 0 text", buffer.replica_id ); - assert_eq!( - buffer.selection_sets().collect::>(), - first_buffer.selection_sets().collect::>() - ); - assert_eq!( - buffer - .all_selection_ranges::() - .collect::>(), - first_buffer - .all_selection_ranges::() - .collect::>() - ); buffer.check_invariants(); } } diff --git a/crates/text/src/text.rs b/crates/text/src/text.rs index 525cbc4366..5da3c7043e 100644 --- a/crates/text/src/text.rs +++ b/crates/text/src/text.rs @@ -13,7 +13,7 @@ pub mod subscription; mod tests; pub use anchor::*; -use anyhow::{anyhow, Result}; +use anyhow::Result; use clock::ReplicaId; use collections::{HashMap, HashSet}; use locator::Locator; @@ -71,17 +71,11 @@ pub struct Transaction { end: clock::Global, edits: Vec, ranges: Vec>, - selections_before: HashMap]>>, - selections_after: HashMap]>>, first_edit_at: Instant, last_edit_at: Instant, } impl Transaction { - pub fn starting_selection_set_ids<'a>(&'a self) -> impl Iterator + 'a { - self.selections_before.keys().copied() - } - fn push_edit(&mut self, edit: &EditOperation) { self.edits.push(edit.timestamp.local()); self.end.observe(edit.timestamp.local()); @@ -158,12 +152,7 @@ impl History { self.ops.insert(op.timestamp.local(), op); } - fn start_transaction( - &mut self, - start: clock::Global, - selections_before: HashMap]>>, - now: Instant, - ) -> Option { + fn start_transaction(&mut self, start: clock::Global, now: Instant) -> Option { self.transaction_depth += 1; if self.transaction_depth == 1 { let id = self.next_transaction_id; @@ -174,8 +163,6 @@ impl History { end: start, edits: Vec::new(), ranges: Vec::new(), - selections_before, - selections_after: Default::default(), first_edit_at: now, last_edit_at: now, }); @@ -185,11 +172,7 @@ impl History { } } - fn end_transaction( - &mut self, - selections_after: HashMap]>>, - now: Instant, - ) -> Option<&Transaction> { + fn end_transaction(&mut self, now: Instant) -> Option<&Transaction> { assert_ne!(self.transaction_depth, 0); self.transaction_depth -= 1; if self.transaction_depth == 0 { @@ -198,7 +181,6 @@ impl History { None } else { let transaction = self.undo_stack.last_mut().unwrap(); - transaction.selections_after = selections_after; transaction.last_edit_at = now; Some(transaction) } @@ -234,9 +216,6 @@ impl History { if let Some(transaction) = transactions_to_merge.last_mut() { last_transaction.last_edit_at = transaction.last_edit_at; - last_transaction - .selections_after - .extend(transaction.selections_after.drain()); last_transaction.end = transaction.end.clone(); } } @@ -558,7 +537,7 @@ impl Buffer { None }; - self.start_transaction(None); + self.start_transaction(); let timestamp = InsertionTimestamp { replica_id: self.replica_id, local: self.local_clock.tick().value, @@ -570,7 +549,7 @@ impl Buffer { self.history.push_undo(edit.timestamp.local()); self.last_edit = edit.timestamp.local(); self.snapshot.version.observe(edit.timestamp.local()); - self.end_transaction(None); + self.end_transaction(); edit } @@ -1149,56 +1128,20 @@ impl Buffer { self.history.undo_stack.last() } - pub fn start_transaction( - &mut self, - selection_set_ids: impl IntoIterator, - ) -> Option { - self.start_transaction_at(selection_set_ids, Instant::now()) + pub fn start_transaction(&mut self) -> Option { + self.start_transaction_at(Instant::now()) } - pub fn start_transaction_at( - &mut self, - selection_set_ids: impl IntoIterator, - now: Instant, - ) -> Option { - let selections = selection_set_ids - .into_iter() - .map(|set_id| { - let set = self - .selection_sets - .get(&set_id) - .expect("invalid selection set id"); - (set_id, set.selections.clone()) - }) - .collect(); - self.history - .start_transaction(self.version.clone(), selections, now) + pub fn start_transaction_at(&mut self, now: Instant) -> Option { + self.history.start_transaction(self.version.clone(), now) } - pub fn end_transaction( - &mut self, - selection_set_ids: impl IntoIterator, - ) -> Option<(TransactionId, clock::Global)> { - self.end_transaction_at(selection_set_ids, Instant::now()) + pub fn end_transaction(&mut self) -> Option<(TransactionId, clock::Global)> { + self.end_transaction_at(Instant::now()) } - pub fn end_transaction_at( - &mut self, - selection_set_ids: impl IntoIterator, - now: Instant, - ) -> Option<(TransactionId, clock::Global)> { - let selections = selection_set_ids - .into_iter() - .map(|set_id| { - let set = self - .selection_sets - .get(&set_id) - .expect("invalid selection set id"); - (set_id, set.selections.clone()) - }) - .collect(); - - if let Some(transaction) = self.history.end_transaction(selections, now) { + pub fn end_transaction_at(&mut self, now: Instant) -> Option<(TransactionId, clock::Global)> { + if let Some(transaction) = self.history.end_transaction(now) { let id = transaction.id; let since = transaction.start.clone(); self.history.group(); @@ -1221,31 +1164,21 @@ impl Buffer { self.history.ops.values() } - pub fn undo(&mut self) -> Option<(TransactionId, Vec)> { + pub fn undo(&mut self) -> Option<(TransactionId, Operation)> { if let Some(transaction) = self.history.pop_undo().cloned() { let transaction_id = transaction.id; - let selections = transaction.selections_before.clone(); - let mut ops = Vec::new(); - ops.push(self.undo_or_redo(transaction).unwrap()); - for (set_id, selections) in selections { - ops.extend(self.restore_selection_set(set_id, selections)); - } - Some((transaction_id, ops)) + let op = self.undo_or_redo(transaction).unwrap(); + Some((transaction_id, op)) } else { None } } - pub fn redo(&mut self) -> Option<(TransactionId, Vec)> { + pub fn redo(&mut self) -> Option<(TransactionId, Operation)> { if let Some(transaction) = self.history.pop_redo().cloned() { let transaction_id = transaction.id; - let selections = transaction.selections_after.clone(); - let mut ops = Vec::new(); - ops.push(self.undo_or_redo(transaction).unwrap()); - for (set_id, selections) in selections { - ops.extend(self.restore_selection_set(set_id, selections)); - } - Some((transaction_id, ops)) + let op = self.undo_or_redo(transaction).unwrap(); + Some((transaction_id, op)) } else { None } @@ -1275,125 +1208,6 @@ impl Buffer { pub fn subscribe(&mut self) -> Subscription { self.subscriptions.subscribe() } - - pub fn selection_set(&self, set_id: SelectionSetId) -> Result<&SelectionSet> { - self.selection_sets - .get(&set_id) - .ok_or_else(|| anyhow!("invalid selection set id {:?}", set_id)) - } - - pub fn selection_sets(&self) -> impl Iterator { - self.selection_sets.iter() - } - - fn build_anchor_selection_set( - &self, - selections: &[Selection], - ) -> Arc<[Selection]> { - Arc::from( - selections - .iter() - .map(|selection| Selection { - id: selection.id, - start: self.anchor_before(&selection.start), - end: self.anchor_before(&selection.end), - reversed: selection.reversed, - goal: selection.goal, - }) - .collect::>(), - ) - } - - pub fn update_selection_set( - &mut self, - set_id: SelectionSetId, - selections: &[Selection], - ) -> Result { - let selections = self.build_anchor_selection_set(selections); - let set = self - .selection_sets - .get_mut(&set_id) - .ok_or_else(|| anyhow!("invalid selection set id {:?}", set_id))?; - set.selections = selections.clone(); - Ok(Operation::UpdateSelections { - set_id, - selections, - lamport_timestamp: self.lamport_clock.tick(), - }) - } - - pub fn restore_selection_set( - &mut self, - set_id: SelectionSetId, - selections: Arc<[Selection]>, - ) -> Result { - let set = self - .selection_sets - .get_mut(&set_id) - .ok_or_else(|| anyhow!("invalid selection set id {:?}", set_id))?; - set.selections = selections.clone(); - Ok(Operation::UpdateSelections { - set_id, - selections, - lamport_timestamp: self.lamport_clock.tick(), - }) - } - - pub fn add_selection_set(&mut self, selections: &[Selection]) -> Operation { - let selections = self.build_anchor_selection_set(selections); - let set_id = self.lamport_clock.tick(); - self.selection_sets.insert( - set_id, - SelectionSet { - id: set_id, - selections: selections.clone(), - active: false, - }, - ); - Operation::UpdateSelections { - set_id, - selections, - lamport_timestamp: set_id, - } - } - - pub fn add_raw_selection_set(&mut self, id: SelectionSetId, selections: SelectionSet) { - self.selection_sets.insert(id, selections); - } - - pub fn set_active_selection_set( - &mut self, - set_id: Option, - ) -> Result { - if let Some(set_id) = set_id { - assert_eq!(set_id.replica_id, self.replica_id()); - } - - for (id, set) in &mut self.selection_sets { - if id.replica_id == self.local_clock.replica_id { - if Some(*id) == set_id { - set.active = true; - } else { - set.active = false; - } - } - } - - Ok(Operation::SetActiveSelections { - set_id, - lamport_timestamp: self.lamport_clock.tick(), - }) - } - - pub fn remove_selection_set(&mut self, set_id: SelectionSetId) -> Result { - self.selection_sets - .remove(&set_id) - .ok_or_else(|| anyhow!("invalid selection set id {:?}", set_id))?; - Ok(Operation::RemoveSelections { - set_id, - lamport_timestamp: self.lamport_clock.tick(), - }) - } } #[cfg(any(test, feature = "test-support"))] @@ -1434,42 +1248,6 @@ impl Buffer { (old_ranges, new_text, Operation::Edit(op)) } - pub fn randomly_mutate(&mut self, rng: &mut T) -> Vec - where - T: rand::Rng, - { - use rand::prelude::*; - - let mut ops = vec![self.randomly_edit(rng, 5).2]; - - // Randomly add, remove or mutate selection sets. - let replica_selection_sets = &self - .selection_sets() - .map(|(set_id, _)| *set_id) - .filter(|set_id| self.replica_id == set_id.replica_id) - .collect::>(); - let set_id = replica_selection_sets.choose(rng); - if set_id.is_some() && rng.gen_bool(1.0 / 6.0) { - ops.push(self.remove_selection_set(*set_id.unwrap()).unwrap()); - } else { - let mut ranges = Vec::new(); - for _ in 0..5 { - ranges.push(self.random_byte_range(0, rng)); - } - let new_selections = self.selections_from_ranges(ranges).unwrap(); - - let op = if set_id.is_none() || rng.gen_bool(1.0 / 5.0) { - self.add_selection_set(&new_selections) - } else { - self.update_selection_set(*set_id.unwrap(), &new_selections) - .unwrap() - }; - ops.push(op); - } - - ops - } - pub fn randomly_undo_redo(&mut self, rng: &mut impl rand::Rng) -> Vec { use rand::prelude::*; @@ -1486,73 +1264,6 @@ impl Buffer { } ops } - - fn selections_from_ranges(&self, ranges: I) -> Result>> - where - I: IntoIterator>, - { - use std::sync::atomic::{self, AtomicUsize}; - - static NEXT_SELECTION_ID: AtomicUsize = AtomicUsize::new(0); - - let mut ranges = ranges.into_iter().collect::>(); - ranges.sort_unstable_by_key(|range| range.start); - - let mut selections = Vec::>::with_capacity(ranges.len()); - for mut range in ranges { - let mut reversed = false; - if range.start > range.end { - reversed = true; - std::mem::swap(&mut range.start, &mut range.end); - } - - if let Some(selection) = selections.last_mut() { - if selection.end >= range.start { - selection.end = range.end; - continue; - } - } - - selections.push(Selection { - id: NEXT_SELECTION_ID.fetch_add(1, atomic::Ordering::SeqCst), - start: range.start, - end: range.end, - reversed, - goal: SelectionGoal::None, - }); - } - Ok(selections) - } - - #[cfg(test)] - pub fn selection_ranges<'a, D>(&'a self, set_id: SelectionSetId) -> Result>> - where - D: TextDimension, - { - Ok(self - .selection_set(set_id)? - .selections(self) - .map(move |selection| { - if selection.reversed { - selection.end..selection.start - } else { - selection.start..selection.end - } - }) - .collect()) - } - - #[cfg(test)] - pub fn all_selection_ranges<'a, D>( - &'a self, - ) -> impl 'a + Iterator>)> - where - D: TextDimension, - { - self.selection_sets - .keys() - .map(move |set_id| (*set_id, self.selection_ranges(*set_id).unwrap())) - } } impl Deref for Buffer {