diff --git a/zed/src/editor.rs b/zed/src/editor.rs index 4919da9103..4d2a1fdc17 100644 --- a/zed/src/editor.rs +++ b/zed/src/editor.rs @@ -5,7 +5,7 @@ pub mod movement; use crate::{ settings::{Settings, StyleId}, - util::post_inc, + util::{post_inc, Bias}, workspace, worktree::FileHandle, }; @@ -723,9 +723,7 @@ impl Editor { let mut new_selections = Vec::new(); self.buffer.update(cx, |buffer, cx| { let edit_ranges = old_selections.iter().map(|(_, range)| range.clone()); - if let Err(error) = buffer.edit(edit_ranges, text.as_str(), Some(cx)) { - log::error!("error inserting text: {}", error); - }; + buffer.edit(edit_ranges, text.as_str(), Some(cx)); let text_len = text.len() as isize; let mut delta = 0_isize; new_selections = old_selections @@ -4139,12 +4137,6 @@ mod tests { } } -#[derive(Copy, Clone)] -pub enum Bias { - Left, - Right, -} - trait RangeExt { fn sorted(&self) -> Range; fn to_inclusive(&self) -> RangeInclusive; diff --git a/zed/src/editor/buffer.rs b/zed/src/editor/buffer.rs index 7fd9c4c9d6..68ddb22b5a 100644 --- a/zed/src/editor/buffer.rs +++ b/zed/src/editor/buffer.rs @@ -13,12 +13,12 @@ use similar::{ChangeTag, TextDiff}; use tree_sitter::{InputEdit, Parser, QueryCursor}; use crate::{ - editor::Bias, language::{Language, Tree}, operation_queue::{self, OperationQueue}, settings::{StyleId, ThemeMap}, - sum_tree::{self, FilterCursor, SeekBias, SumTree}, + sum_tree::{self, FilterCursor, SumTree}, time::{self, ReplicaId}, + util::Bias, worktree::FileHandle, }; use anyhow::{anyhow, Result}; @@ -28,8 +28,7 @@ use std::{ cell::RefCell, cmp, hash::BuildHasher, - iter::{self, Iterator}, - mem, + iter::Iterator, ops::{Deref, DerefMut, Range}, str, sync::Arc, @@ -109,7 +108,6 @@ pub struct Buffer { fragments: SumTree, visible_text: Rope, deleted_text: Rope, - insertion_splits: HashMap>, pub version: time::Global, saved_version: time::Global, saved_mtime: SystemTime, @@ -171,7 +169,7 @@ impl History { } fn push(&mut self, op: EditOperation) { - self.ops.insert(op.id, op); + self.ops.insert(op.timestamp.local(), op); } fn start_transaction( @@ -328,61 +326,62 @@ struct Diff { changes: Vec<(ChangeTag, usize)>, } -#[derive(Clone, Eq, PartialEq, Debug)] -pub struct Insertion { - id: time::Local, - parent_id: time::Local, - offset_in_parent: usize, - lamport_timestamp: time::Lamport, +#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)] +struct InsertionTimestamp { + replica_id: ReplicaId, + local: time::Seq, + lamport: time::Seq, +} + +impl InsertionTimestamp { + fn local(&self) -> time::Local { + time::Local { + replica_id: self.replica_id, + value: self.local, + } + } + + fn lamport(&self) -> time::Lamport { + time::Lamport { + replica_id: self.replica_id, + value: self.lamport, + } + } } #[derive(Eq, PartialEq, Clone, Debug)] struct Fragment { - id: FragmentId, - insertion: Arc, - range_in_insertion: Range, + timestamp: InsertionTimestamp, + len: usize, + visible: bool, deletions: HashSet, max_undos: time::Global, - visible: bool, } #[derive(Eq, PartialEq, Clone, Debug)] pub struct FragmentSummary { text: FragmentTextSummary, - max_fragment_id: FragmentId, max_version: time::Global, + min_insertion_version: time::Global, + max_insertion_version: time::Global, } -#[derive(Default, Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Default, Clone, Debug, PartialEq, Eq)] struct FragmentTextSummary { visible: usize, deleted: usize, } impl<'a> sum_tree::Dimension<'a, FragmentSummary> for FragmentTextSummary { - fn add_summary(&mut self, summary: &'a FragmentSummary) { + fn add_summary(&mut self, summary: &'a FragmentSummary, _: &Option) { self.visible += summary.text.visible; self.deleted += summary.text.deleted; } } -#[derive(Eq, PartialEq, Clone, Debug)] -struct InsertionSplit { - extent: usize, - fragment_id: FragmentId, -} - -#[derive(Eq, PartialEq, Clone, Debug)] -struct InsertionSplitSummary { - extent: usize, -} - #[derive(Clone, Debug, Eq, PartialEq)] pub enum Operation { - Edit { - edit: EditOperation, - lamport_timestamp: time::Lamport, - }, + Edit(EditOperation), Undo { undo: UndoOperation, lamport_timestamp: time::Lamport, @@ -396,12 +395,9 @@ pub enum Operation { #[derive(Clone, Debug, Eq, PartialEq)] pub struct EditOperation { - id: time::Local, - start_id: time::Local, - start_offset: usize, - end_id: time::Local, - end_offset: usize, - version_in_range: time::Global, + timestamp: InsertionTimestamp, + version: time::Global, + ranges: Vec>, new_text: Option, } @@ -474,53 +470,19 @@ impl Buffer { saved_mtime = UNIX_EPOCH; } - let mut visible_text = Rope::new(); - let mut insertion_splits = HashMap::default(); let mut fragments = SumTree::new(); - let base_text = Rope::from(history.base_text.as_ref()); - let base_insertion = Arc::new(Insertion { - id: time::Local::default(), - parent_id: time::Local::default(), - offset_in_parent: 0, - lamport_timestamp: time::Lamport::default(), - }); - - insertion_splits.insert( - base_insertion.id, - SumTree::from_item( - InsertionSplit { - fragment_id: FragmentId::min_value().clone(), - extent: 0, - }, - &(), - ), - ); - fragments.push( - Fragment::new( - FragmentId::min_value().clone(), - base_insertion.clone(), - 0..0, - ), - &(), - ); - - if base_text.len() > 0 { - let base_fragment_id = - FragmentId::between(&FragmentId::min_value(), &FragmentId::max_value()); - let range_in_insertion = 0..base_text.len(); - - visible_text = base_text.clone(); - insertion_splits.get_mut(&base_insertion.id).unwrap().push( - InsertionSplit { - fragment_id: base_fragment_id.clone(), - extent: range_in_insertion.end, - }, - &(), - ); + let visible_text = Rope::from(history.base_text.as_ref()); + if visible_text.len() > 0 { fragments.push( - Fragment::new(base_fragment_id, base_insertion, range_in_insertion.clone()), - &(), + Fragment { + timestamp: Default::default(), + len: visible_text.len(), + visible: true, + deletions: Default::default(), + max_undos: Default::default(), + }, + &None, ); } @@ -528,7 +490,6 @@ impl Buffer { visible_text, deleted_text: Rope::new(), fragments, - insertion_splits, version: time::Global::new(), saved_version: time::Global::new(), last_edit: time::Local::default(), @@ -781,12 +742,11 @@ impl Buffer { match tag { ChangeTag::Equal => offset += len, ChangeTag::Delete => { - operations.extend_from_slice(&self.edit(Some(range), "", Some(cx)).unwrap()) + operations.push(self.edit(Some(range), "", Some(cx)).unwrap()) } ChangeTag::Insert => { - operations.extend_from_slice( - &self - .edit(Some(offset..offset), &diff.new_text[range], Some(cx)) + operations.push( + self.edit(Some(offset..offset), &diff.new_text[range], Some(cx)) .unwrap(), ); offset += len; @@ -825,7 +785,7 @@ impl Buffer { } pub fn len(&self) -> usize { - self.fragments.extent::() + self.fragments.extent::(&None) } pub fn line_len(&self, row: u32) -> u32 { @@ -871,9 +831,10 @@ impl Buffer { pub fn edits_since<'a>(&'a self, since: time::Global) -> impl 'a + Iterator { let since_2 = since.clone(); - let cursor = self - .fragments - .filter(move |summary| summary.max_version.changed_since(&since_2)); + let cursor = self.fragments.filter( + move |summary| summary.max_version.changed_since(&since_2), + &None, + ); Edits { deleted_text: &self.deleted_text, @@ -951,56 +912,60 @@ impl Buffer { pub fn edit( &mut self, - old_ranges: I, + ranges_iter: I, new_text: T, cx: Option<&mut ModelContext>, - ) -> Result> + ) -> Option where I: IntoIterator>, S: ToOffset, T: Into, { - self.start_transaction_at(None, Instant::now())?; - let new_text = new_text.into(); - let old_ranges = old_ranges - .into_iter() - .map(|range| range.start.to_offset(self)..range.end.to_offset(self)) - .collect::>>(); - let new_text = if new_text.len() > 0 { Some(new_text) } else { None }; - let has_new_text = new_text.is_some(); - let ops = self.splice_fragments( - old_ranges - .into_iter() - .filter(|old_range| has_new_text || old_range.end > old_range.start), - new_text.into(), - ); - for op in &ops { - if let Operation::Edit { edit, .. } = op { - self.history.push(edit.clone()); - self.history.push_undo(edit.id); + // Skip invalid ranges and coalesce contiguous ones. + let mut ranges: Vec> = Vec::new(); + for range in ranges_iter { + let range = range.start.to_offset(self)..range.end.to_offset(self); + if has_new_text || !range.is_empty() { + if let Some(prev_range) = ranges.last_mut() { + if prev_range.end >= range.start { + prev_range.end = cmp::max(prev_range.end, range.end); + } else { + ranges.push(range); + } + } else { + ranges.push(range); + } } } - if let Some(op) = ops.last() { - if let Operation::Edit { edit, .. } = op { - self.last_edit = edit.id; - self.version.observe(edit.id); - } else { - unreachable!() - } + if ranges.is_empty() { + None + } else { + self.start_transaction_at(None, Instant::now()).unwrap(); + let timestamp = InsertionTimestamp { + replica_id: self.replica_id, + local: self.local_clock.tick().value, + lamport: self.lamport_clock.tick().value, + }; + let edit = self.apply_local_edit(&ranges, new_text, timestamp); + + self.history.push(edit.clone()); + self.history.push_undo(edit.timestamp.local()); + self.last_edit = edit.timestamp.local(); + self.version.observe(edit.timestamp.local()); + + self.end_transaction_at(None, Instant::now(), cx).unwrap(); + + Some(Operation::Edit(edit)) } - - self.end_transaction_at(None, Instant::now(), cx)?; - - Ok(ops) } fn did_edit(&self, was_dirty: bool, cx: &mut ModelContext) { @@ -1120,23 +1085,15 @@ impl Buffer { fn apply_op(&mut self, op: Operation) -> Result<()> { match op { - Operation::Edit { - edit, - lamport_timestamp, - .. - } => { - if !self.version.observed(edit.id) { - self.apply_edit( - edit.start_id, - edit.start_offset, - edit.end_id, - edit.end_offset, + Operation::Edit(edit) => { + if !self.version.observed(edit.timestamp.local()) { + self.apply_remote_edit( + &edit.version, + &edit.ranges, edit.new_text.as_deref(), - &edit.version_in_range, - edit.id, - lamport_timestamp, - )?; - self.version.observe(edit.id); + edit.timestamp, + ); + self.version.observe(edit.timestamp.local()); self.history.push(edit); } } @@ -1167,154 +1124,149 @@ impl Buffer { Ok(()) } - fn apply_edit( + fn apply_remote_edit( &mut self, - start_id: time::Local, - start_offset: usize, - end_id: time::Local, - end_offset: usize, - mut new_text: Option<&str>, - version_in_range: &time::Global, - local_timestamp: time::Local, - lamport_timestamp: time::Lamport, - ) -> Result<()> { - let start_fragment_id = self.resolve_fragment_id(start_id, start_offset)?; - let end_fragment_id = self.resolve_fragment_id(end_id, end_offset)?; + version: &time::Global, + ranges: &[Range], + new_text: Option<&str>, + timestamp: InsertionTimestamp, + ) { + if ranges.is_empty() { + return; + } - let mut old_visible_text = Rope::new(); - let mut old_deleted_text = Rope::new(); - let mut old_fragments = SumTree::new(); - mem::swap(&mut old_visible_text, &mut self.visible_text); - mem::swap(&mut old_deleted_text, &mut self.deleted_text); - mem::swap(&mut old_fragments, &mut self.fragments); - - let mut fragments_cursor = old_fragments.cursor::(); - - let mut new_fragments = - fragments_cursor.slice(&FragmentIdRef::new(&start_fragment_id), SeekBias::Left, &()); + let cx = Some(version.clone()); let mut new_ropes = - RopeBuilder::new(old_visible_text.cursor(0), old_deleted_text.cursor(0)); + RopeBuilder::new(self.visible_text.cursor(0), self.deleted_text.cursor(0)); + let mut old_fragments = self.fragments.cursor::(); + let mut new_fragments = + old_fragments.slice(&VersionedOffset::Offset(ranges[0].start), Bias::Left, &cx); new_ropes.push_tree(new_fragments.summary().text); - let start_fragment = fragments_cursor.item().unwrap(); - if start_offset == start_fragment.range_in_insertion.end { - let fragment = fragments_cursor.item().unwrap().clone(); - new_ropes.push_fragment(&fragment, fragment.visible); - new_fragments.push(fragment, &()); - fragments_cursor.next(); - } + let mut fragment_start = old_fragments.start().offset(); + for range in ranges { + let fragment_end = old_fragments.end(&cx).offset(); - while let Some(fragment) = fragments_cursor.item() { - if new_text.is_none() && fragment.id > end_fragment_id { - break; + // If the current fragment ends before this range, then jump ahead to the first fragment + // that extends past the start of this range, reusing any intervening fragments. + if fragment_end < range.start { + // If the current fragment has been partially consumed, then consume the rest of it + // and advance to the next fragment before slicing. + if fragment_start > old_fragments.start().offset() { + if fragment_end > fragment_start { + let mut suffix = old_fragments.item().unwrap().clone(); + suffix.len = fragment_end - fragment_start; + new_ropes.push_fragment(&suffix, suffix.visible); + new_fragments.push(suffix, &None); + } + old_fragments.next(&cx); + } + + let slice = + old_fragments.slice(&VersionedOffset::Offset(range.start), Bias::Left, &cx); + new_ropes.push_tree(slice.summary().text); + new_fragments.push_tree(slice, &None); + fragment_start = old_fragments.start().offset(); } - let mut fragment = fragment.clone(); + // If we are at the end of a non-concurrent fragment, advance to the next one. + let fragment_end = old_fragments.end(&cx).offset(); + if fragment_end == range.start && fragment_end > fragment_start { + let mut fragment = old_fragments.item().unwrap().clone(); + fragment.len = fragment_end - fragment_start; + new_ropes.push_fragment(&fragment, fragment.visible); + new_fragments.push(fragment, &None); + old_fragments.next(&cx); + fragment_start = old_fragments.start().offset(); + } - if fragment.id == start_fragment_id || fragment.id == end_fragment_id { - let split_start = if start_fragment_id == fragment.id { - start_offset - } else { - fragment.range_in_insertion.start - }; - let split_end = if end_fragment_id == fragment.id { - end_offset - } else { - fragment.range_in_insertion.end - }; - let (before_range, within_range, after_range) = self.split_fragment( - fragments_cursor.prev_item().as_ref().unwrap(), - &fragment, - split_start..split_end, - ); - let insertion = if let Some(new_text) = new_text { - let prev_fragment = fragments_cursor.prev_item(); - Some(self.build_fragment_to_insert( - before_range.as_ref().or(prev_fragment).unwrap(), - within_range.as_ref().or(after_range.as_ref()), - new_text, - local_timestamp, - lamport_timestamp, - )) - } else { - None - }; - if let Some(fragment) = before_range { - new_ropes.push_fragment(&fragment, fragment.visible); - new_fragments.push(fragment, &()); - } - if let Some(fragment) = insertion { - new_ropes.push_str(new_text.take().unwrap()); - new_fragments.push(fragment, &()); - } - if let Some(mut fragment) = within_range { - let fragment_was_visible = fragment.visible; - if fragment.was_visible(&version_in_range, &self.undo_map) { - fragment.deletions.insert(local_timestamp); - if fragment.visible { - fragment.visible = false; - } - } - - new_ropes.push_fragment(&fragment, fragment_was_visible); - new_fragments.push(fragment, &()); - } - if let Some(fragment) = after_range { - new_ropes.push_fragment(&fragment, fragment.visible); - new_fragments.push(fragment, &()); - } - } else { - if new_text.is_some() && lamport_timestamp > fragment.insertion.lamport_timestamp { - let new_text = new_text.take().unwrap(); - let fragment = self.build_fragment_to_insert( - fragments_cursor.prev_item().as_ref().unwrap(), - Some(&fragment), - new_text, - local_timestamp, - lamport_timestamp, - ); - new_ropes.push_str(new_text); - new_fragments.push(fragment, &()); - } - - let fragment_was_visible = fragment.visible; - if fragment.id < end_fragment_id - && fragment.was_visible(&version_in_range, &self.undo_map) + // Skip over insertions that are concurrent to this edit, but have a lower lamport + // timestamp. + while let Some(fragment) = old_fragments.item() { + if fragment_start == range.start + && fragment.timestamp.lamport() > timestamp.lamport() { - fragment.deletions.insert(local_timestamp); - if fragment.visible { - fragment.visible = false; - } + new_ropes.push_fragment(fragment, fragment.visible); + new_fragments.push(fragment.clone(), &None); + old_fragments.next(&cx); + debug_assert_eq!(fragment_start, range.start); + } else { + break; } + } + debug_assert!(fragment_start <= range.start); - new_ropes.push_fragment(&fragment, fragment_was_visible); - new_fragments.push(fragment, &()); + // Preserve any portion of the current fragment that precedes this range. + if fragment_start < range.start { + let mut prefix = old_fragments.item().unwrap().clone(); + prefix.len = range.start - fragment_start; + fragment_start = range.start; + new_ropes.push_fragment(&prefix, prefix.visible); + new_fragments.push(prefix, &None); } - fragments_cursor.next(); + // Insert the new text before any existing fragments within the range. + if let Some(new_text) = new_text { + new_ropes.push_str(new_text); + new_fragments.push( + Fragment { + timestamp, + len: new_text.len(), + deletions: Default::default(), + max_undos: Default::default(), + visible: true, + }, + &None, + ); + } + + // Advance through every fragment that intersects this range, marking the intersecting + // portions as deleted. + while fragment_start < range.end { + let fragment = old_fragments.item().unwrap(); + let fragment_end = old_fragments.end(&cx).offset(); + let mut intersection = fragment.clone(); + let intersection_end = cmp::min(range.end, fragment_end); + if fragment.was_visible(version, &self.undo_map) { + intersection.len = intersection_end - fragment_start; + intersection.deletions.insert(timestamp.local()); + intersection.visible = false; + } + if intersection.len > 0 { + new_ropes.push_fragment(&intersection, fragment.visible); + new_fragments.push(intersection, &None); + fragment_start = intersection_end; + } + if fragment_end <= range.end { + old_fragments.next(&cx); + } + } } - if let Some(new_text) = new_text { - let fragment = self.build_fragment_to_insert( - fragments_cursor.prev_item().as_ref().unwrap(), - None, - new_text, - local_timestamp, - lamport_timestamp, - ); - new_ropes.push_str(new_text); - new_fragments.push(fragment, &()); + // If the current fragment has been partially consumed, then consume the rest of it + // and advance to the next fragment before slicing. + if fragment_start > old_fragments.start().offset() { + let fragment_end = old_fragments.end(&cx).offset(); + if fragment_end > fragment_start { + let mut suffix = old_fragments.item().unwrap().clone(); + suffix.len = fragment_end - fragment_start; + new_ropes.push_fragment(&suffix, suffix.visible); + new_fragments.push(suffix, &None); + } + old_fragments.next(&cx); } + let suffix = old_fragments.suffix(&cx); + new_ropes.push_tree(suffix.summary().text); + new_fragments.push_tree(suffix, &None); let (visible_text, deleted_text) = new_ropes.finish(); - new_fragments.push_tree(fragments_cursor.suffix(&()), &()); + drop(old_fragments); self.fragments = new_fragments; self.visible_text = visible_text; self.deleted_text = deleted_text; - self.local_clock.observe(local_timestamp); - self.lamport_clock.observe(lamport_timestamp); - Ok(()) + self.local_clock.observe(timestamp.local()); + self.lamport_clock.observe(timestamp.lamport()); } pub fn undo(&mut self, mut cx: Option<&mut ModelContext>) -> Vec { @@ -1387,85 +1339,60 @@ impl Buffer { } fn apply_undo(&mut self, undo: UndoOperation) -> Result<()> { - let mut new_fragments; - let mut old_visible_text = Rope::new(); - let mut old_deleted_text = Rope::new(); - mem::swap(&mut old_visible_text, &mut self.visible_text); - mem::swap(&mut old_deleted_text, &mut self.deleted_text); - let mut new_ropes = - RopeBuilder::new(old_visible_text.cursor(0), old_deleted_text.cursor(0)); - self.undo_map.insert(undo); let edit = &self.history.ops[&undo.edit_id]; - let start_fragment_id = self.resolve_fragment_id(edit.start_id, edit.start_offset)?; - let end_fragment_id = self.resolve_fragment_id(edit.end_id, edit.end_offset)?; + let version = Some(edit.version.clone()); - let mut fragments_cursor = self.fragments.cursor::(); + let mut old_fragments = self.fragments.cursor::(); + old_fragments.seek(&VersionedOffset::Offset(0), Bias::Left, &version); - if edit.start_id == edit.end_id && edit.start_offset == edit.end_offset { - let splits = &self.insertion_splits[&undo.edit_id]; - let mut insertion_splits = splits.cursor::<(), ()>().map(|s| &s.fragment_id).peekable(); + let mut new_fragments = SumTree::new(); + let mut new_ropes = + RopeBuilder::new(self.visible_text.cursor(0), self.deleted_text.cursor(0)); - let first_split_id = insertion_splits.next().unwrap(); - new_fragments = - fragments_cursor.slice(&FragmentIdRef::new(first_split_id), SeekBias::Left, &()); - new_ropes.push_tree(new_fragments.summary().text); + for range in &edit.ranges { + let mut end_offset = old_fragments.end(&version).offset(); - loop { - let mut fragment = fragments_cursor.item().unwrap().clone(); - let was_visible = fragment.visible; - fragment.visible = fragment.is_visible(&self.undo_map); - fragment.max_undos.observe(undo.id); - - new_ropes.push_fragment(&fragment, was_visible); - new_fragments.push(fragment.clone(), &()); - - fragments_cursor.next(); - if let Some(split_id) = insertion_splits.next() { - let slice = - fragments_cursor.slice(&FragmentIdRef::new(split_id), SeekBias::Left, &()); - new_ropes.push_tree(slice.summary().text); - new_fragments.push_tree(slice, &()); - } else { - break; - } + if end_offset < range.start { + let preceding_fragments = old_fragments.slice( + &VersionedOffset::Offset(range.start), + Bias::Left, + &version, + ); + new_ropes.push_tree(preceding_fragments.summary().text); + new_fragments.push_tree(preceding_fragments, &None); } - } else { - new_fragments = fragments_cursor.slice( - &FragmentIdRef::new(&start_fragment_id), - SeekBias::Left, - &(), - ); - new_ropes.push_tree(new_fragments.summary().text); - while let Some(fragment) = fragments_cursor.item() { - if fragment.id > end_fragment_id { - break; - } else { + while end_offset <= range.end { + if let Some(fragment) = old_fragments.item() { let mut fragment = fragment.clone(); let fragment_was_visible = fragment.visible; - if edit.version_in_range.observed(fragment.insertion.id) - || fragment.insertion.id == undo.edit_id + if fragment.was_visible(&edit.version, &self.undo_map) + || fragment.timestamp.local() == edit.timestamp.local() { fragment.visible = fragment.is_visible(&self.undo_map); fragment.max_undos.observe(undo.id); } - new_ropes.push_fragment(&fragment, fragment_was_visible); - new_fragments.push(fragment, &()); - fragments_cursor.next(); + new_fragments.push(fragment, &None); + + old_fragments.next(&version); + end_offset = old_fragments.end(&version).offset(); + } else { + break; } } } - new_fragments.push_tree(fragments_cursor.suffix(&()), &()); - let (visible_text, deleted_text) = new_ropes.finish(); - drop(fragments_cursor); + let suffix = old_fragments.suffix(&version); + new_ropes.push_tree(suffix.summary().text); + new_fragments.push_tree(suffix, &None); + drop(old_fragments); + let (visible_text, deleted_text) = new_ropes.finish(); self.fragments = new_fragments; self.visible_text = visible_text; self.deleted_text = deleted_text; - Ok(()) } @@ -1489,25 +1416,17 @@ impl Buffer { false } else { match op { - Operation::Edit { edit, .. } => { - self.version.observed(edit.start_id) - && self.version.observed(edit.end_id) - && edit.version_in_range <= self.version - } + Operation::Edit(edit) => self.version >= edit.version, Operation::Undo { undo, .. } => self.version.observed(undo.edit_id), Operation::UpdateSelections { selections, .. } => { if let Some(selections) = selections { selections.iter().all(|selection| { - let contains_start = match selection.start { - Anchor::Middle { insertion_id, .. } => { - self.version.observed(insertion_id) - } + let contains_start = match &selection.start { + Anchor::Middle { version, .. } => self.version >= *version, _ => true, }; - let contains_end = match selection.end { - Anchor::Middle { insertion_id, .. } => { - self.version.observed(insertion_id) - } + let contains_end = match &selection.end { + Anchor::Middle { version, .. } => self.version >= *version, _ => true, }; contains_start && contains_end @@ -1520,522 +1439,152 @@ impl Buffer { } } - fn resolve_fragment_id(&self, edit_id: time::Local, offset: usize) -> Result { - let split_tree = self - .insertion_splits - .get(&edit_id) - .ok_or_else(|| anyhow!("invalid operation"))?; - let mut cursor = split_tree.cursor::(); - cursor.seek(&offset, SeekBias::Left, &()); - Ok(cursor - .item() - .ok_or_else(|| anyhow!("invalid operation"))? - .fragment_id - .clone()) - } - - fn splice_fragments(&mut self, mut old_ranges: I, new_text: Option) -> Vec - where - I: Iterator>, - { - let mut cur_range = old_ranges.next(); - if cur_range.is_none() { - return Vec::new(); - } - - let mut ops = Vec::with_capacity(old_ranges.size_hint().0); - - let mut old_fragments = SumTree::new(); - let mut old_visible_text = Rope::new(); - let mut old_deleted_text = Rope::new(); - mem::swap(&mut old_visible_text, &mut self.visible_text); - mem::swap(&mut old_deleted_text, &mut self.deleted_text); - mem::swap(&mut old_fragments, &mut self.fragments); - - let mut fragments_cursor = old_fragments.cursor::(); - let mut new_fragments = - fragments_cursor.slice(&cur_range.as_ref().unwrap().start, SeekBias::Right, &()); + fn apply_local_edit( + &mut self, + ranges: &[Range], + new_text: Option, + timestamp: InsertionTimestamp, + ) -> EditOperation { + let mut edit = EditOperation { + timestamp, + version: self.version(), + ranges: Vec::with_capacity(ranges.len()), + new_text: None, + }; let mut new_ropes = - RopeBuilder::new(old_visible_text.cursor(0), old_deleted_text.cursor(0)); + RopeBuilder::new(self.visible_text.cursor(0), self.deleted_text.cursor(0)); + let mut old_fragments = self.fragments.cursor::(); + let mut new_fragments = old_fragments.slice(&ranges[0].start, Bias::Right, &None); new_ropes.push_tree(new_fragments.summary().text); - let mut start_id = None; - let mut start_offset = None; - let mut end_id = None; - let mut end_offset = None; - let mut version_in_range = time::Global::new(); + let mut fragment_start = old_fragments.start().visible; + for range in ranges { + let fragment_end = old_fragments.end(&None).visible; - let mut local_timestamp = self.local_clock.tick(); - let mut lamport_timestamp = self.lamport_clock.tick(); - - while cur_range.is_some() && fragments_cursor.item().is_some() { - let mut fragment = fragments_cursor.item().unwrap().clone(); - let fragment_summary = fragments_cursor.item_summary().unwrap(); - let mut fragment_start = *fragments_cursor.start(); - let mut fragment_end = fragment_start + fragment.visible_len(); - let fragment_was_visible = fragment.visible; - - let old_split_tree = self - .insertion_splits - .remove(&fragment.insertion.id) - .unwrap(); - let mut splits_cursor = old_split_tree.cursor::(); - let mut new_split_tree = - splits_cursor.slice(&fragment.range_in_insertion.start, SeekBias::Right, &()); - - // Find all splices that start or end within the current fragment. Then, split the - // fragment and reassemble it in both trees accounting for the deleted and the newly - // inserted text. - while cur_range.as_ref().map_or(false, |r| r.start < fragment_end) { - let range = cur_range.clone().unwrap(); - if range.start > fragment_start { - let mut prefix = fragment.clone(); - prefix.range_in_insertion.end = - prefix.range_in_insertion.start + (range.start - fragment_start); - prefix.id = - FragmentId::between(&new_fragments.last().unwrap().id, &fragment.id); - fragment.range_in_insertion.start = prefix.range_in_insertion.end; - - new_ropes.push_fragment(&prefix, prefix.visible); - new_fragments.push(prefix.clone(), &()); - new_split_tree.push( - InsertionSplit { - extent: prefix.range_in_insertion.end - prefix.range_in_insertion.start, - fragment_id: prefix.id, - }, - &(), - ); - fragment_start = range.start; - } - - if range.end == fragment_start { - end_id = Some(new_fragments.last().unwrap().insertion.id); - end_offset = Some(new_fragments.last().unwrap().range_in_insertion.end); - } else if range.end == fragment_end { - end_id = Some(fragment.insertion.id); - end_offset = Some(fragment.range_in_insertion.end); - } - - if range.start == fragment_start { - start_id = Some(new_fragments.last().unwrap().insertion.id); - start_offset = Some(new_fragments.last().unwrap().range_in_insertion.end); - - if let Some(new_text) = new_text.clone() { - let new_fragment = self.build_fragment_to_insert( - &new_fragments.last().unwrap(), - Some(&fragment), - &new_text, - local_timestamp, - lamport_timestamp, - ); - - new_ropes.push_str(&new_text); - new_fragments.push(new_fragment, &()); + // If the current fragment ends before this range, then jump ahead to the first fragment + // that extends past the start of this range, reusing any intervening fragments. + if fragment_end < range.start { + // If the current fragment has been partially consumed, then consume the rest of it + // and advance to the next fragment before slicing. + if fragment_start > old_fragments.start().visible { + if fragment_end > fragment_start { + let mut suffix = old_fragments.item().unwrap().clone(); + suffix.len = fragment_end - fragment_start; + new_ropes.push_fragment(&suffix, suffix.visible); + new_fragments.push(suffix, &None); } + old_fragments.next(&None); } - if range.end < fragment_end { - if range.end > fragment_start { - let mut prefix = fragment.clone(); - prefix.range_in_insertion.end = - prefix.range_in_insertion.start + (range.end - fragment_start); - prefix.id = - FragmentId::between(&new_fragments.last().unwrap().id, &fragment.id); - version_in_range.observe_all(&fragment_summary.max_version); - if prefix.visible { - prefix.deletions.insert(local_timestamp); - prefix.visible = false; - } - fragment.range_in_insertion.start = prefix.range_in_insertion.end; - new_ropes.push_fragment(&prefix, fragment_was_visible); - new_fragments.push(prefix.clone(), &()); - new_split_tree.push( - InsertionSplit { - extent: prefix.range_in_insertion.end - - prefix.range_in_insertion.start, - fragment_id: prefix.id, - }, - &(), - ); - fragment_start = range.end; - end_id = Some(fragment.insertion.id); - end_offset = Some(fragment.range_in_insertion.start); - } - } else { - version_in_range.observe_all(&fragment_summary.max_version); - if fragment.visible { - fragment.deletions.insert(local_timestamp); - fragment.visible = false; - } - } - - // If the splice ends inside this fragment, we can advance to the next splice and - // check if it also intersects the current fragment. Otherwise we break out of the - // loop and find the first fragment that the splice does not contain fully. - if range.end <= fragment_end { - ops.push(Operation::Edit { - edit: EditOperation { - id: local_timestamp, - start_id: start_id.unwrap(), - start_offset: start_offset.unwrap(), - end_id: end_id.unwrap(), - end_offset: end_offset.unwrap(), - version_in_range, - new_text: new_text.clone(), - }, - lamport_timestamp, - }); - - start_id = None; - start_offset = None; - end_id = None; - end_offset = None; - version_in_range = time::Global::new(); - cur_range = old_ranges.next(); - if cur_range.is_some() { - local_timestamp = self.local_clock.tick(); - lamport_timestamp = self.lamport_clock.tick(); - } - } else { - break; - } + let slice = old_fragments.slice(&range.start, Bias::Right, &None); + new_ropes.push_tree(slice.summary().text); + new_fragments.push_tree(slice, &None); + fragment_start = old_fragments.start().visible; } - new_split_tree.push( - InsertionSplit { - extent: fragment.range_in_insertion.end - fragment.range_in_insertion.start, - fragment_id: fragment.id.clone(), - }, - &(), - ); - splits_cursor.next(); - new_split_tree.push_tree( - splits_cursor.slice(&old_split_tree.extent::(), SeekBias::Right, &()), - &(), - ); - self.insertion_splits - .insert(fragment.insertion.id, new_split_tree); - new_ropes.push_fragment(&fragment, fragment_was_visible); - new_fragments.push(fragment, &()); + let full_range_start = range.start + old_fragments.start().deleted; - // Scan forward until we find a fragment that is not fully contained by the current splice. - fragments_cursor.next(); - if let Some(range) = cur_range.clone() { - while let Some(fragment) = fragments_cursor.item() { - let fragment_summary = fragments_cursor.item_summary().unwrap(); - let fragment_was_visible = fragment.visible; - fragment_start = *fragments_cursor.start(); - fragment_end = fragment_start + fragment.visible_len(); - if range.start < fragment_start && range.end >= fragment_end { - let mut new_fragment = fragment.clone(); - version_in_range.observe_all(&fragment_summary.max_version); - if new_fragment.visible { - new_fragment.deletions.insert(local_timestamp); - new_fragment.visible = false; - } - - new_ropes.push_fragment(&new_fragment, fragment_was_visible); - new_fragments.push(new_fragment, &()); - fragments_cursor.next(); - - if range.end == fragment_end { - end_id = Some(fragment.insertion.id); - end_offset = Some(fragment.range_in_insertion.end); - ops.push(Operation::Edit { - edit: EditOperation { - id: local_timestamp, - start_id: start_id.unwrap(), - start_offset: start_offset.unwrap(), - end_id: end_id.unwrap(), - end_offset: end_offset.unwrap(), - version_in_range, - new_text: new_text.clone(), - }, - lamport_timestamp, - }); - - start_id = None; - start_offset = None; - end_id = None; - end_offset = None; - version_in_range = time::Global::new(); - - cur_range = old_ranges.next(); - if cur_range.is_some() { - local_timestamp = self.local_clock.tick(); - lamport_timestamp = self.lamport_clock.tick(); - } - break; - } - } else { - break; - } - } - - // If the splice we are currently evaluating starts after the end of the fragment - // that the cursor is parked at, we should seek to the next splice's start range - // and push all the fragments in between into the new tree. - if cur_range.as_ref().map_or(false, |r| r.start > fragment_end) { - let slice = fragments_cursor.slice( - &cur_range.as_ref().unwrap().start, - SeekBias::Right, - &(), - ); - new_ropes.push_tree(slice.summary().text); - new_fragments.push_tree(slice, &()); - } + // Preserve any portion of the current fragment that precedes this range. + if fragment_start < range.start { + let mut prefix = old_fragments.item().unwrap().clone(); + prefix.len = range.start - fragment_start; + new_ropes.push_fragment(&prefix, prefix.visible); + new_fragments.push(prefix, &None); + fragment_start = range.start; } - } - // Handle range that is at the end of the buffer if it exists. There should never be - // multiple because ranges must be disjoint. - if cur_range.is_some() { - debug_assert_eq!(old_ranges.next(), None); - let last_fragment = new_fragments.last().unwrap(); - ops.push(Operation::Edit { - edit: EditOperation { - id: local_timestamp, - start_id: last_fragment.insertion.id, - start_offset: last_fragment.range_in_insertion.end, - end_id: last_fragment.insertion.id, - end_offset: last_fragment.range_in_insertion.end, - version_in_range: time::Global::new(), - // TODO: avoid cloning the String. - new_text: new_text.clone(), - }, - lamport_timestamp, - }); - - if let Some(new_text) = new_text { - let new_fragment = self.build_fragment_to_insert( - &last_fragment, - None, - &new_text, - local_timestamp, - lamport_timestamp, + // Insert the new text before any existing fragments within the range. + if let Some(new_text) = new_text.as_deref() { + new_ropes.push_str(new_text); + new_fragments.push( + Fragment { + timestamp, + len: new_text.len(), + deletions: Default::default(), + max_undos: Default::default(), + visible: true, + }, + &None, ); - - new_ropes.push_str(&new_text); - new_fragments.push(new_fragment, &()); } + + // Advance through every fragment that intersects this range, marking the intersecting + // portions as deleted. + while fragment_start < range.end { + let fragment = old_fragments.item().unwrap(); + let fragment_end = old_fragments.end(&None).visible; + let mut intersection = fragment.clone(); + let intersection_end = cmp::min(range.end, fragment_end); + if fragment.visible { + intersection.len = intersection_end - fragment_start; + intersection.deletions.insert(timestamp.local()); + intersection.visible = false; + } + if intersection.len > 0 { + new_ropes.push_fragment(&intersection, fragment.visible); + new_fragments.push(intersection, &None); + fragment_start = intersection_end; + } + if fragment_end <= range.end { + old_fragments.next(&None); + } + } + + let full_range_end = range.end + old_fragments.start().deleted; + edit.ranges.push(full_range_start..full_range_end); } - new_fragments.push_tree(fragments_cursor.suffix(&()), &()); + // If the current fragment has been partially consumed, then consume the rest of it + // and advance to the next fragment before slicing. + if fragment_start > old_fragments.start().visible { + let fragment_end = old_fragments.end(&None).visible; + if fragment_end > fragment_start { + let mut suffix = old_fragments.item().unwrap().clone(); + suffix.len = fragment_end - fragment_start; + new_ropes.push_fragment(&suffix, suffix.visible); + new_fragments.push(suffix, &None); + } + old_fragments.next(&None); + } + + let suffix = old_fragments.suffix(&None); + new_ropes.push_tree(suffix.summary().text); + new_fragments.push_tree(suffix, &None); let (visible_text, deleted_text) = new_ropes.finish(); + drop(old_fragments); self.fragments = new_fragments; self.visible_text = visible_text; self.deleted_text = deleted_text; - ops - } - - fn split_fragment( - &mut self, - prev_fragment: &Fragment, - fragment: &Fragment, - range: Range, - ) -> (Option, Option, Option) { - debug_assert!(range.start >= fragment.range_in_insertion.start); - debug_assert!(range.start <= fragment.range_in_insertion.end); - debug_assert!(range.end <= fragment.range_in_insertion.end); - debug_assert!(range.end >= fragment.range_in_insertion.start); - - if range.end == fragment.range_in_insertion.start { - (None, None, Some(fragment.clone())) - } else if range.start == fragment.range_in_insertion.end { - (Some(fragment.clone()), None, None) - } else if range.start == fragment.range_in_insertion.start - && range.end == fragment.range_in_insertion.end - { - (None, Some(fragment.clone()), None) - } else { - let mut prefix = fragment.clone(); - - let after_range = if range.end < fragment.range_in_insertion.end { - let mut suffix = prefix.clone(); - suffix.range_in_insertion.start = range.end; - prefix.range_in_insertion.end = range.end; - prefix.id = FragmentId::between(&prev_fragment.id, &suffix.id); - Some(suffix) - } else { - None - }; - - let within_range = if range.start != range.end { - let mut suffix = prefix.clone(); - suffix.range_in_insertion.start = range.start; - prefix.range_in_insertion.end = range.start; - prefix.id = FragmentId::between(&prev_fragment.id, &suffix.id); - Some(suffix) - } else { - None - }; - - let before_range = if range.start > fragment.range_in_insertion.start { - Some(prefix) - } else { - None - }; - - let old_split_tree = self - .insertion_splits - .remove(&fragment.insertion.id) - .unwrap(); - let mut cursor = old_split_tree.cursor::(); - let mut new_split_tree = - cursor.slice(&fragment.range_in_insertion.start, SeekBias::Right, &()); - - if let Some(ref fragment) = before_range { - new_split_tree.push( - InsertionSplit { - extent: range.start - fragment.range_in_insertion.start, - fragment_id: fragment.id.clone(), - }, - &(), - ); - } - - if let Some(ref fragment) = within_range { - new_split_tree.push( - InsertionSplit { - extent: range.end - range.start, - fragment_id: fragment.id.clone(), - }, - &(), - ); - } - - if let Some(ref fragment) = after_range { - new_split_tree.push( - InsertionSplit { - extent: fragment.range_in_insertion.end - range.end, - fragment_id: fragment.id.clone(), - }, - &(), - ); - } - - cursor.next(); - new_split_tree.push_tree( - cursor.slice(&old_split_tree.extent::(), SeekBias::Right, &()), - &(), - ); - - self.insertion_splits - .insert(fragment.insertion.id, new_split_tree); - - (before_range, within_range, after_range) - } - } - - fn build_fragment_to_insert( - &mut self, - prev_fragment: &Fragment, - next_fragment: Option<&Fragment>, - text: &str, - insertion_id: time::Local, - lamport_timestamp: time::Lamport, - ) -> Fragment { - let new_fragment_id = FragmentId::between( - &prev_fragment.id, - next_fragment - .map(|f| &f.id) - .unwrap_or(&FragmentId::max_value()), - ); - - let range_in_insertion = 0..text.len(); - let mut split_tree = SumTree::new(); - split_tree.push( - InsertionSplit { - extent: range_in_insertion.len(), - fragment_id: new_fragment_id.clone(), - }, - &(), - ); - self.insertion_splits.insert(insertion_id, split_tree); - - Fragment::new( - new_fragment_id, - Arc::new(Insertion { - id: insertion_id, - parent_id: prev_fragment.insertion.id, - offset_in_parent: prev_fragment.range_in_insertion.end, - lamport_timestamp, - }), - range_in_insertion, - ) + edit.new_text = new_text; + edit } pub fn anchor_before(&self, position: T) -> Anchor { - self.anchor_at(position, AnchorBias::Left) + self.anchor_at(position, Bias::Left) } pub fn anchor_after(&self, position: T) -> Anchor { - self.anchor_at(position, AnchorBias::Right) + self.anchor_at(position, Bias::Right) } - pub fn anchor_at(&self, position: T, bias: AnchorBias) -> Anchor { + pub fn anchor_at(&self, position: T, bias: Bias) -> Anchor { let offset = position.to_offset(self); let max_offset = self.len(); assert!(offset <= max_offset, "offset is out of range"); - let seek_bias; - match bias { - AnchorBias::Left => { - if offset == 0 { - return Anchor::Start; - } else { - seek_bias = SeekBias::Left; - } - } - AnchorBias::Right => { - if offset == max_offset { - return Anchor::End; - } else { - seek_bias = SeekBias::Right; - } - } - }; - - let mut cursor = self.fragments.cursor::(); - cursor.seek(&offset, seek_bias, &()); - let fragment = cursor.item().unwrap(); - let offset_in_fragment = offset - cursor.start(); - let offset_in_insertion = fragment.range_in_insertion.start + offset_in_fragment; - let anchor = Anchor::Middle { - insertion_id: fragment.insertion.id, - offset: offset_in_insertion, - bias, - }; - anchor - } - - fn fragment_id_for_anchor(&self, anchor: &Anchor) -> Result<&FragmentId> { - match anchor { - Anchor::Start => Ok(FragmentId::max_value()), - Anchor::End => Ok(FragmentId::min_value()), + if offset == 0 && bias == Bias::Left { + Anchor::Start + } else if offset == max_offset && bias == Bias::Right { + Anchor::End + } else { + let mut cursor = self.fragments.cursor::(); + cursor.seek(&offset, bias, &None); Anchor::Middle { - insertion_id, - offset, + offset: offset + cursor.start().deleted, bias, - .. - } => { - let seek_bias = match bias { - AnchorBias::Left => SeekBias::Left, - AnchorBias::Right => SeekBias::Right, - }; - - let splits = self - .insertion_splits - .get(&insertion_id) - .ok_or_else(|| anyhow!("split does not exist for insertion id"))?; - let mut splits_cursor = splits.cursor::(); - splits_cursor.seek(offset, seek_bias, &()); - splits_cursor - .item() - .ok_or_else(|| anyhow!("split offset is out of range")) - .map(|split| &split.fragment_id) + version: self.version(), } } } @@ -2045,32 +1594,53 @@ impl Buffer { Anchor::Start => TextSummary::default(), Anchor::End => self.text_summary(), Anchor::Middle { - insertion_id, offset, bias, + version, } => { - let seek_bias = match bias { - AnchorBias::Left => SeekBias::Left, - AnchorBias::Right => SeekBias::Right, + let mut cursor = self + .fragments + .cursor::(); + cursor.seek( + &VersionedOffset::Offset(*offset), + *bias, + &Some(version.clone()), + ); + let fragment = cursor.item().unwrap(); + let overshoot = if fragment.visible { + offset - cursor.start().0.offset() + } else { + 0 }; - let splits = self - .insertion_splits - .get(&insertion_id) - .expect("split does not exist for insertion id"); - let mut splits_cursor = splits.cursor::(); - splits_cursor.seek(offset, seek_bias, &()); - let split = splits_cursor.item().expect("split offset is out of range"); + self.text_summary_for_range(0..cursor.start().1 + overshoot) + } + } + } - let mut fragments_cursor = self.fragments.cursor::(); - fragments_cursor.seek(&FragmentIdRef::new(&split.fragment_id), SeekBias::Left, &()); - let fragment = fragments_cursor.item().expect("fragment id does not exist"); - - let mut ix = *fragments_cursor.start(); - if fragment.visible { - ix += offset - fragment.range_in_insertion.start; - } - self.text_summary_for_range(0..ix) + fn full_offset_for_anchor(&self, anchor: &Anchor) -> usize { + match anchor { + Anchor::Start => 0, + Anchor::End => { + let summary = self.fragments.summary(); + summary.text.visible + summary.text.deleted + } + Anchor::Middle { + offset, + bias, + version, + } => { + let mut cursor = self + .fragments + .cursor::(); + cursor.seek( + &VersionedOffset::Offset(*offset), + *bias, + &Some(version.clone()), + ); + let overshoot = offset - cursor.start().0.offset(); + let summary = cursor.start().1; + summary.visible + summary.deleted + overshoot } } } @@ -2098,7 +1668,6 @@ impl Clone for Buffer { fragments: self.fragments.clone(), visible_text: self.visible_text.clone(), deleted_text: self.deleted_text.clone(), - insertion_splits: self.insertion_splits.clone(), version: self.version.clone(), saved_version: self.saved_version.clone(), saved_mtime: self.saved_mtime, @@ -2208,7 +1777,8 @@ impl<'a> RopeBuilder<'a> { } fn push_fragment(&mut self, fragment: &Fragment, was_visible: bool) { - self.push(fragment.len(), was_visible, fragment.visible) + debug_assert!(fragment.len > 0); + self.push(fragment.len, was_visible, fragment.visible) } fn push(&mut self, len: usize, was_visible: bool, is_visible: bool) { @@ -2264,42 +1834,42 @@ impl<'a, F: Fn(&FragmentSummary) -> bool> Iterator for Edits<'a, F> { if !fragment.was_visible(&self.since, &self.undos) && fragment.visible { if let Some(ref mut change) = change { if change.new_range.end == new_offset { - change.new_range.end += fragment.len(); - self.delta += fragment.len() as isize; + change.new_range.end += fragment.len; + self.delta += fragment.len as isize; } else { break; } } else { change = Some(Edit { old_range: old_offset..old_offset, - new_range: new_offset..new_offset + fragment.len(), + new_range: new_offset..new_offset + fragment.len, old_lines: Point::zero(), }); - self.delta += fragment.len() as isize; + self.delta += fragment.len as isize; } } else if fragment.was_visible(&self.since, &self.undos) && !fragment.visible { let deleted_start = self.cursor.start().deleted; - let old_lines = self.deleted_text.to_point(deleted_start + fragment.len()) + let old_lines = self.deleted_text.to_point(deleted_start + fragment.len) - self.deleted_text.to_point(deleted_start); if let Some(ref mut change) = change { if change.new_range.end == new_offset { - change.old_range.end += fragment.len(); + change.old_range.end += fragment.len; change.old_lines += &old_lines; - self.delta -= fragment.len() as isize; + self.delta -= fragment.len as isize; } else { break; } } else { change = Some(Edit { - old_range: old_offset..old_offset + fragment.len(), + old_range: old_offset..old_offset + fragment.len, new_range: new_offset..new_offset, old_lines, }); - self.delta -= fragment.len() as isize; + self.delta -= fragment.len as isize; } } - self.cursor.next(); + self.cursor.next(&None); } change @@ -2426,103 +1996,20 @@ impl<'a> Iterator for HighlightedChunks<'a> { } } -#[derive(Ord, PartialOrd, Eq, PartialEq, Clone, Debug)] -struct FragmentId(Arc<[u16]>); - -lazy_static! { - static ref FRAGMENT_ID_EMPTY: FragmentId = FragmentId(Arc::from([])); - static ref FRAGMENT_ID_MIN_VALUE: FragmentId = FragmentId(Arc::from([0 as u16])); - static ref FRAGMENT_ID_MAX_VALUE: FragmentId = FragmentId(Arc::from([u16::max_value()])); -} - -impl Default for FragmentId { - fn default() -> Self { - FRAGMENT_ID_EMPTY.clone() - } -} - -impl FragmentId { - fn min_value() -> &'static Self { - &FRAGMENT_ID_MIN_VALUE - } - - fn max_value() -> &'static Self { - &FRAGMENT_ID_MAX_VALUE - } - - fn between(left: &Self, right: &Self) -> Self { - Self::between_with_max(left, right, u16::max_value()) - } - - fn between_with_max(left: &Self, right: &Self, max_value: u16) -> Self { - let mut new_entries = Vec::new(); - - let left_entries = left.0.iter().cloned().chain(iter::repeat(0)); - let right_entries = right.0.iter().cloned().chain(iter::repeat(max_value)); - for (l, r) in left_entries.zip(right_entries) { - let interval = r - l; - if interval > 1 { - new_entries.push(l + cmp::max(1, cmp::min(8, interval / 2))); - break; - } else { - new_entries.push(l); - } - } - - FragmentId(Arc::from(new_entries)) - } -} - -#[derive(Ord, PartialOrd, Eq, PartialEq, Clone, Debug, Default)] -struct FragmentIdRef<'a>(Option<&'a FragmentId>); - -impl<'a> FragmentIdRef<'a> { - fn new(id: &'a FragmentId) -> Self { - Self(Some(id)) - } -} - -impl<'a> sum_tree::Dimension<'a, FragmentSummary> for FragmentIdRef<'a> { - fn add_summary(&mut self, summary: &'a FragmentSummary) { - self.0 = Some(&summary.max_fragment_id) - } -} - impl Fragment { - fn new(id: FragmentId, insertion: Arc, range_in_insertion: Range) -> Self { - Self { - id, - insertion, - range_in_insertion, - deletions: Default::default(), - max_undos: Default::default(), - visible: true, - } - } - fn is_visible(&self, undos: &UndoMap) -> bool { - !undos.is_undone(self.insertion.id) && self.deletions.iter().all(|d| undos.is_undone(*d)) + !undos.is_undone(self.timestamp.local()) + && self.deletions.iter().all(|d| undos.is_undone(*d)) } fn was_visible(&self, version: &time::Global, undos: &UndoMap) -> bool { - (version.observed(self.insertion.id) && !undos.was_undone(self.insertion.id, version)) + (version.observed(self.timestamp.local()) + && !undos.was_undone(self.timestamp.local(), version)) && self .deletions .iter() .all(|d| !version.observed(*d) || undos.was_undone(*d, version)) } - - fn len(&self) -> usize { - self.range_in_insertion.len() - } - - fn visible_len(&self) -> usize { - if self.visible { - self.range_in_insertion.len() - } else { - 0 - } - } } impl sum_tree::Item for Fragment { @@ -2530,43 +2017,50 @@ impl sum_tree::Item for Fragment { fn summary(&self) -> Self::Summary { let mut max_version = time::Global::new(); - max_version.observe(self.insertion.id); + max_version.observe(self.timestamp.local()); for deletion in &self.deletions { max_version.observe(*deletion); } - max_version.observe_all(&self.max_undos); + max_version.join(&self.max_undos); + let mut min_insertion_version = time::Global::new(); + min_insertion_version.observe(self.timestamp.local()); + let max_insertion_version = min_insertion_version.clone(); if self.visible { FragmentSummary { text: FragmentTextSummary { - visible: self.len(), + visible: self.len, deleted: 0, }, - max_fragment_id: self.id.clone(), max_version, + min_insertion_version, + max_insertion_version, } } else { FragmentSummary { text: FragmentTextSummary { visible: 0, - deleted: self.len(), + deleted: self.len, }, - max_fragment_id: self.id.clone(), max_version, + min_insertion_version, + max_insertion_version, } } } } impl sum_tree::Summary for FragmentSummary { - type Context = (); + type Context = Option; fn add_summary(&mut self, other: &Self, _: &Self::Context) { self.text.visible += &other.text.visible; self.text.deleted += &other.text.deleted; - debug_assert!(self.max_fragment_id <= other.max_fragment_id); - self.max_fragment_id = other.max_fragment_id.clone(); - self.max_version.observe_all(&other.max_version); + self.max_version.join(&other.max_version); + self.min_insertion_version + .meet(&other.min_insertion_version); + self.max_insertion_version + .join(&other.max_insertion_version); } } @@ -2574,45 +2068,65 @@ impl Default for FragmentSummary { fn default() -> Self { FragmentSummary { text: FragmentTextSummary::default(), - max_fragment_id: FragmentId::min_value().clone(), max_version: time::Global::new(), + min_insertion_version: time::Global::new(), + max_insertion_version: time::Global::new(), } } } impl<'a> sum_tree::Dimension<'a, FragmentSummary> for usize { - fn add_summary(&mut self, summary: &FragmentSummary) { + fn add_summary(&mut self, summary: &FragmentSummary, _: &Option) { *self += summary.text.visible; } } -impl sum_tree::Item for InsertionSplit { - type Summary = InsertionSplitSummary; +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +enum VersionedOffset { + Offset(usize), + InvalidVersion, +} - fn summary(&self) -> Self::Summary { - InsertionSplitSummary { - extent: self.extent, +impl VersionedOffset { + fn offset(&self) -> usize { + if let Self::Offset(offset) = self { + *offset + } else { + panic!("invalid version") } } } -impl sum_tree::Summary for InsertionSplitSummary { - type Context = (); - - fn add_summary(&mut self, other: &Self, _: &()) { - self.extent += other.extent; - } -} - -impl Default for InsertionSplitSummary { +impl Default for VersionedOffset { fn default() -> Self { - InsertionSplitSummary { extent: 0 } + Self::Offset(0) } } -impl<'a> sum_tree::Dimension<'a, InsertionSplitSummary> for usize { - fn add_summary(&mut self, summary: &InsertionSplitSummary) { - *self += summary.extent; +impl<'a> sum_tree::Dimension<'a, FragmentSummary> for VersionedOffset { + fn add_summary(&mut self, summary: &'a FragmentSummary, cx: &Option) { + if let Self::Offset(offset) = self { + let version = cx.as_ref().unwrap(); + if *version >= summary.max_insertion_version { + *offset += summary.text.visible + summary.text.deleted; + } else if !summary + .min_insertion_version + .iter() + .all(|t| !version.observed(*t)) + { + *self = Self::InvalidVersion; + } + } + } +} + +impl<'a> sum_tree::SeekDimension<'a, FragmentSummary> for VersionedOffset { + fn cmp(&self, other: &Self, _: &Option) -> cmp::Ordering { + match (self, other) { + (Self::Offset(a), Self::Offset(b)) => Ord::cmp(a, b), + (Self::Offset(_), Self::InvalidVersion) => cmp::Ordering::Less, + (Self::InvalidVersion, _) => unreachable!(), + } } } @@ -2623,9 +2137,7 @@ impl Operation { fn lamport_timestamp(&self) -> time::Lamport { match self { - Operation::Edit { - lamport_timestamp, .. - } => *lamport_timestamp, + Operation::Edit(edit) => edit.timestamp.lamport(), Operation::Undo { lamport_timestamp, .. } => *lamport_timestamp, @@ -2707,7 +2219,8 @@ mod tests { use std::{ cell::RefCell, cmp::Ordering, - fs, + env, fs, + iter::FromIterator, rc::Rc, sync::atomic::{self, AtomicUsize}, }; @@ -2752,8 +2265,8 @@ mod tests { // An edit emits an edited event, followed by a dirtied event, // since the buffer was previously in a clean state. - let ops = buffer.edit(Some(2..4), "XYZ", Some(cx)).unwrap(); - buffer_ops.extend_from_slice(&ops); + let op = buffer.edit(Some(2..4), "XYZ", Some(cx)).unwrap(); + buffer_ops.push(op); // An empty transaction does not emit any events. buffer.start_transaction(None).unwrap(); @@ -2762,10 +2275,8 @@ mod tests { // A transaction containing two edits emits one edited event. now += Duration::from_secs(1); buffer.start_transaction_at(None, now).unwrap(); - let ops = buffer.edit(Some(5..5), "u", Some(cx)).unwrap(); - buffer_ops.extend_from_slice(&ops); - let ops = buffer.edit(Some(6..6), "w", Some(cx)).unwrap(); - buffer_ops.extend_from_slice(&ops); + buffer_ops.push(buffer.edit(Some(5..5), "u", Some(cx)).unwrap()); + buffer_ops.push(buffer.edit(Some(6..6), "w", Some(cx)).unwrap()); buffer.end_transaction_at(None, now, Some(cx)).unwrap(); // Undoing a transaction emits one edited event. @@ -2791,7 +2302,16 @@ mod tests { #[gpui::test] fn test_random_edits(cx: &mut gpui::MutableAppContext) { - for seed in 0..100 { + let iterations = env::var("ITERATIONS") + .map(|i| i.parse().expect("invalid `ITERATIONS` variable")) + .unwrap_or(100); + let operations = env::var("OPERATIONS") + .map(|i| i.parse().expect("invalid `OPERATIONS` variable")) + .unwrap_or(10); + let start_seed = + env::var("SEED").map_or(0, |seed| seed.parse().expect("invalid `SEED` variable")); + + for seed in start_seed..start_seed + iterations { println!("{:?}", seed); let mut rng = &mut StdRng::seed_from_u64(seed); @@ -2802,12 +2322,23 @@ mod tests { cx.add_model(|cx| { let mut buffer = Buffer::new(0, reference_string.as_str(), cx); let mut buffer_versions = Vec::new(); - for _i in 0..10 { + log::info!( + "buffer text {:?}, version: {:?}", + buffer.text(), + buffer.version() + ); + + for _i in 0..operations { let (old_ranges, new_text, _) = buffer.randomly_mutate(rng, None); for old_range in old_ranges.iter().rev() { reference_string.replace_range(old_range.clone(), &new_text); } assert_eq!(buffer.text(), reference_string); + log::info!( + "buffer text {:?}, version: {:?}", + buffer.text(), + buffer.version() + ); if rng.gen_bool(0.25) { buffer.randomly_undo_redo(rng); @@ -2826,20 +2357,29 @@ mod tests { } for mut old_buffer in buffer_versions { + let edits = buffer + .edits_since(old_buffer.version.clone()) + .collect::>(); + + log::info!( + "mutating old buffer version {:?}, text: {:?}, edits since: {:?}", + old_buffer.version(), + old_buffer.text(), + edits, + ); + let mut delta = 0_isize; for Edit { old_range, new_range, .. - } in buffer.edits_since(old_buffer.version.clone()) + } in edits { let old_len = old_range.end - old_range.start; let new_len = new_range.end - new_range.start; let old_start = (old_range.start as isize + delta) as usize; let new_text: String = buffer.text_for_range(new_range).collect(); - old_buffer - .edit(Some(old_start..old_start + old_len), new_text, None) - .unwrap(); + old_buffer.edit(Some(old_start..old_start + old_len), new_text, None); delta += new_len as isize - old_len as isize; } @@ -2969,26 +2509,6 @@ mod tests { }); } - #[test] - fn test_fragment_ids() { - for seed in 0..10 { - let rng = &mut StdRng::seed_from_u64(seed); - - let mut ids = vec![FragmentId(Arc::from([0])), FragmentId(Arc::from([4]))]; - for _i in 0..100 { - let index = rng.gen_range(1..ids.len()); - - let left = ids[index - 1].clone(); - let right = ids[index].clone(); - ids.insert(index, FragmentId::between_with_max(&left, &right, 4)); - - let mut sorted_ids = ids.clone(); - sorted_ids.sort(); - assert_eq!(ids, sorted_ids); - } - } - } - #[gpui::test] fn test_anchors(cx: &mut gpui::MutableAppContext) { cx.add_model(|cx| { @@ -3294,7 +2814,7 @@ mod tests { buffer.add_selection_set( (0..3) .map(|row| { - let anchor = buffer.anchor_at(Point::new(row, 0), AnchorBias::Right); + let anchor = buffer.anchor_at(Point::new(row, 0), Bias::Right); Selection { id: row as usize, start: anchor.clone(), @@ -3385,25 +2905,25 @@ mod tests { let edit3 = buffer.edit(vec![3..5], "cd", None).unwrap(); assert_eq!(buffer.text(), "1abcdef234"); - buffer.undo_or_redo(edit1[0].edit_id().unwrap()).unwrap(); + buffer.undo_or_redo(edit1.edit_id().unwrap()).unwrap(); assert_eq!(buffer.text(), "1cdef234"); - buffer.undo_or_redo(edit1[0].edit_id().unwrap()).unwrap(); + buffer.undo_or_redo(edit1.edit_id().unwrap()).unwrap(); assert_eq!(buffer.text(), "1abcdef234"); - buffer.undo_or_redo(edit2[0].edit_id().unwrap()).unwrap(); + buffer.undo_or_redo(edit2.edit_id().unwrap()).unwrap(); assert_eq!(buffer.text(), "1abcdx234"); - buffer.undo_or_redo(edit3[0].edit_id().unwrap()).unwrap(); + buffer.undo_or_redo(edit3.edit_id().unwrap()).unwrap(); assert_eq!(buffer.text(), "1abx234"); - buffer.undo_or_redo(edit2[0].edit_id().unwrap()).unwrap(); + buffer.undo_or_redo(edit2.edit_id().unwrap()).unwrap(); assert_eq!(buffer.text(), "1abyzef234"); - buffer.undo_or_redo(edit3[0].edit_id().unwrap()).unwrap(); + buffer.undo_or_redo(edit3.edit_id().unwrap()).unwrap(); assert_eq!(buffer.text(), "1abcdef234"); - buffer.undo_or_redo(edit3[0].edit_id().unwrap()).unwrap(); + buffer.undo_or_redo(edit3.edit_id().unwrap()).unwrap(); assert_eq!(buffer.text(), "1abyzef234"); - buffer.undo_or_redo(edit1[0].edit_id().unwrap()).unwrap(); + buffer.undo_or_redo(edit1.edit_id().unwrap()).unwrap(); assert_eq!(buffer.text(), "1yzef234"); - buffer.undo_or_redo(edit2[0].edit_id().unwrap()).unwrap(); + buffer.undo_or_redo(edit2.edit_id().unwrap()).unwrap(); assert_eq!(buffer.text(), "1234"); buffer @@ -3478,14 +2998,66 @@ mod tests { }); } + #[gpui::test] + fn test_concurrent_edits(cx: &mut gpui::MutableAppContext) { + let text = "abcdef"; + + let buffer1 = cx.add_model(|cx| Buffer::new(1, text, cx)); + let buffer2 = cx.add_model(|cx| Buffer::new(2, text, cx)); + let buffer3 = cx.add_model(|cx| Buffer::new(3, text, cx)); + + let buf1_op = buffer1.update(cx, |buffer, cx| { + let op = buffer.edit(vec![1..2], "12", Some(cx)).unwrap(); + assert_eq!(buffer.text(), "a12cdef"); + op + }); + let buf2_op = buffer2.update(cx, |buffer, cx| { + let op = buffer.edit(vec![3..4], "34", Some(cx)).unwrap(); + assert_eq!(buffer.text(), "abc34ef"); + op + }); + let buf3_op = buffer3.update(cx, |buffer, cx| { + let op = buffer.edit(vec![5..6], "56", Some(cx)).unwrap(); + assert_eq!(buffer.text(), "abcde56"); + op + }); + + buffer1.update(cx, |buffer, _| { + buffer.apply_op(buf2_op.clone()).unwrap(); + buffer.apply_op(buf3_op.clone()).unwrap(); + }); + buffer2.update(cx, |buffer, _| { + buffer.apply_op(buf1_op.clone()).unwrap(); + buffer.apply_op(buf3_op.clone()).unwrap(); + }); + buffer3.update(cx, |buffer, _| { + buffer.apply_op(buf1_op.clone()).unwrap(); + buffer.apply_op(buf2_op.clone()).unwrap(); + }); + + assert_eq!(buffer1.read(cx).text(), "a12c34e56"); + assert_eq!(buffer2.read(cx).text(), "a12c34e56"); + assert_eq!(buffer3.read(cx).text(), "a12c34e56"); + } + #[gpui::test] fn test_random_concurrent_edits(cx: &mut gpui::MutableAppContext) { use crate::test::Network; - const PEERS: usize = 5; + let peers = env::var("PEERS") + .map(|i| i.parse().expect("invalid `PEERS` variable")) + .unwrap_or(5); + let iterations = env::var("ITERATIONS") + .map(|i| i.parse().expect("invalid `ITERATIONS` variable")) + .unwrap_or(100); + let operations = env::var("OPERATIONS") + .map(|i| i.parse().expect("invalid `OPERATIONS` variable")) + .unwrap_or(10); + let start_seed = + env::var("SEED").map_or(0, |seed| seed.parse().expect("invalid `SEED` variable")); - for seed in 0..100 { - println!("{:?}", seed); + for seed in start_seed..start_seed + iterations { + dbg!(seed); let mut rng = &mut StdRng::seed_from_u64(seed); let base_text_len = rng.gen_range(0..10); @@ -3495,20 +3067,23 @@ mod tests { let mut replica_ids = Vec::new(); let mut buffers = Vec::new(); let mut network = Network::new(); - for i in 0..PEERS { + for i in 0..peers { let buffer = cx.add_model(|cx| Buffer::new(i as ReplicaId, base_text.as_str(), cx)); buffers.push(buffer); replica_ids.push(i as u16); network.add_peer(i as u16); } - let mut mutation_count = 10; + log::info!("initial text: {:?}", base_text); + + let mut mutation_count = operations; loop { - let replica_index = rng.gen_range(0..PEERS); + let replica_index = rng.gen_range(0..peers); let replica_id = replica_ids[replica_index]; buffers[replica_index].update(cx, |buffer, _| match rng.gen_range(0..=100) { 0..=50 if mutation_count != 0 => { let (_, _, ops) = buffer.randomly_mutate(&mut rng, None); + log::info!("buffer {} text: {:?}", buffer.replica_id, buffer.text()); network.broadcast(replica_id, ops, &mut rng); mutation_count -= 1; } @@ -3518,9 +3093,15 @@ mod tests { mutation_count -= 1; } 71..=100 if network.has_unreceived(replica_id) => { - buffer - .apply_ops(network.receive(replica_id, &mut rng), None) - .unwrap(); + let ops = network.receive(replica_id, &mut rng); + if !ops.is_empty() { + log::info!( + "peer {} applying {} ops from the network.", + replica_id, + ops.len() + ); + buffer.apply_ops(ops, None).unwrap(); + } } _ => {} }); @@ -3533,7 +3114,12 @@ mod tests { let first_buffer = buffers[0].read(cx); for buffer in &buffers[1..] { let buffer = buffer.read(cx); - assert_eq!(buffer.text(), first_buffer.text()); + assert_eq!( + buffer.text(), + first_buffer.text(), + "Replica {} text != Replica 0 text", + buffer.replica_id + ); assert_eq!( buffer.all_selections().collect::>(), first_buffer.all_selections().collect::>() @@ -3699,7 +3285,7 @@ mod tests { let text = " mod x { mod y { - + } } " @@ -3738,7 +3324,7 @@ mod tests { impl Buffer { fn random_byte_range(&mut self, start_offset: usize, rng: &mut impl Rng) -> Range { let end = self.clip_offset(rng.gen_range(start_offset..=self.len()), Bias::Right); - let start = self.clip_offset(rng.gen_range(start_offset..=end), Bias::Left); + let start = self.clip_offset(rng.gen_range(start_offset..=end), Bias::Right); start..end } @@ -3747,7 +3333,7 @@ mod tests { rng: &mut T, old_range_count: usize, cx: Option<&mut ModelContext>, - ) -> (Vec>, String, Vec) + ) -> (Vec>, String, Option) where T: Rng, { @@ -3761,12 +3347,14 @@ mod tests { } let new_text_len = rng.gen_range(0..10); let new_text: String = RandomCharIter::new(&mut *rng).take(new_text_len).collect(); - - let operations = self - .edit(old_ranges.iter().cloned(), new_text.as_str(), cx) - .unwrap(); - - (old_ranges, new_text, operations) + log::info!( + "mutating buffer {} at {:?}: {:?}", + self.replica_id, + old_ranges, + new_text + ); + let operation = self.edit(old_ranges.iter().cloned(), new_text.as_str(), cx); + (old_ranges, new_text, operation) } pub fn randomly_mutate( @@ -3777,9 +3365,8 @@ mod tests { where T: Rng, { - // Randomly edit - let (old_ranges, new_text, mut operations) = - self.randomly_edit(rng, 5, cx.as_deref_mut()); + let (old_ranges, new_text, operation) = self.randomly_edit(rng, 5, cx.as_deref_mut()); + let mut operations = Vec::from_iter(operation); // Randomly add, remove or mutate selection sets. let replica_selection_sets = &self @@ -3812,8 +3399,9 @@ mod tests { pub fn randomly_undo_redo(&mut self, rng: &mut impl Rng) -> Vec { let mut ops = Vec::new(); - for _ in 0..rng.gen_range(1..5) { + for _ in 0..rng.gen_range(1..=5) { if let Some(edit_id) = self.history.ops.keys().choose(rng).copied() { + log::info!("undoing buffer {} operation {:?}", self.replica_id, edit_id); ops.push(self.undo_or_redo(edit_id).unwrap()); } } @@ -3897,7 +3485,7 @@ mod tests { impl Operation { fn edit_id(&self) -> Option { match self { - Operation::Edit { edit, .. } => Some(edit.id), + Operation::Edit(edit) => Some(edit.timestamp.local()), Operation::Undo { undo, .. } => Some(undo.edit_id), Operation::UpdateSelections { .. } => None, } diff --git a/zed/src/editor/buffer/anchor.rs b/zed/src/editor/buffer/anchor.rs index 3b2687f96d..6715054ada 100644 --- a/zed/src/editor/buffer/anchor.rs +++ b/zed/src/editor/buffer/anchor.rs @@ -1,47 +1,19 @@ use super::Buffer; -use crate::time; +use crate::{time, util::Bias}; use anyhow::Result; -use std::cmp::Ordering; -use std::ops::Range; +use std::{cmp::Ordering, ops::Range}; #[derive(Clone, Eq, PartialEq, Debug, Hash)] pub enum Anchor { Start, End, Middle { - insertion_id: time::Local, offset: usize, - bias: AnchorBias, + bias: Bias, + version: time::Global, }, } -#[derive(Clone, Eq, PartialEq, Debug, Hash)] -pub enum AnchorBias { - Left, - Right, -} - -impl PartialOrd for AnchorBias { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for AnchorBias { - fn cmp(&self, other: &Self) -> Ordering { - use AnchorBias::*; - - if self == other { - return Ordering::Equal; - } - - match (self, other) { - (Left, _) => Ordering::Less, - (Right, _) => Ordering::Greater, - } - } -} - impl Anchor { pub fn cmp(&self, other: &Anchor, buffer: &Buffer) -> Result { if self == other { @@ -55,18 +27,24 @@ impl Anchor { Anchor::Middle { offset: self_offset, bias: self_bias, - .. + version: self_version, }, Anchor::Middle { offset: other_offset, bias: other_bias, - .. + version: other_version, }, - ) => buffer - .fragment_id_for_anchor(self)? - .cmp(buffer.fragment_id_for_anchor(other)?) - .then_with(|| self_offset.cmp(other_offset)) - .then_with(|| self_bias.cmp(other_bias)), + ) => { + let offset_comparison = if self_version == other_version { + self_offset.cmp(other_offset) + } else { + buffer + .full_offset_for_anchor(self) + .cmp(&buffer.full_offset_for_anchor(other)) + }; + + offset_comparison.then_with(|| self_bias.cmp(&other_bias)) + } }) } @@ -74,8 +52,7 @@ impl Anchor { match self { Anchor::Start | Anchor::Middle { - bias: AnchorBias::Left, - .. + bias: Bias::Left, .. } => self.clone(), _ => buffer.anchor_before(self), } @@ -85,8 +62,7 @@ impl Anchor { match self { Anchor::End | Anchor::Middle { - bias: AnchorBias::Right, - .. + bias: Bias::Right, .. } => self.clone(), _ => buffer.anchor_after(self), } diff --git a/zed/src/editor/buffer/rope.rs b/zed/src/editor/buffer/rope.rs index 98b317c0ed..268924c158 100644 --- a/zed/src/editor/buffer/rope.rs +++ b/zed/src/editor/buffer/rope.rs @@ -1,7 +1,7 @@ use super::Point; use crate::{ - editor::Bias, - sum_tree::{self, SeekBias, SumTree}, + sum_tree::{self, SumTree}, + util::Bias, }; use arrayvec::ArrayString; use smallvec::SmallVec; @@ -25,13 +25,13 @@ impl Rope { pub fn append(&mut self, rope: Rope) { let mut chunks = rope.chunks.cursor::<(), ()>(); - chunks.next(); + chunks.next(&()); if let Some(chunk) = chunks.item() { if self.chunks.last().map_or(false, |c| c.0.len() < CHUNK_BASE) || chunk.0.len() < CHUNK_BASE { self.push(&chunk.0); - chunks.next(); + chunks.next(&()); } } @@ -99,11 +99,11 @@ impl Rope { } pub fn len(&self) -> usize { - self.chunks.extent() + self.chunks.extent(&()) } pub fn max_point(&self) -> Point { - self.chunks.extent() + self.chunks.extent(&()) } pub fn cursor(&self, offset: usize) -> Cursor { @@ -129,7 +129,7 @@ impl Rope { pub fn to_point(&self, offset: usize) -> Point { assert!(offset <= self.summary().bytes); let mut cursor = self.chunks.cursor::(); - cursor.seek(&offset, SeekBias::Left, &()); + cursor.seek(&offset, Bias::Left, &()); let overshoot = offset - cursor.start().bytes; cursor.start().lines + cursor @@ -140,14 +140,14 @@ impl Rope { pub fn to_offset(&self, point: Point) -> usize { assert!(point <= self.summary().lines); let mut cursor = self.chunks.cursor::(); - cursor.seek(&point, SeekBias::Left, &()); + cursor.seek(&point, Bias::Left, &()); let overshoot = point - cursor.start().lines; cursor.start().bytes + cursor.item().map_or(0, |chunk| chunk.to_offset(overshoot)) } pub fn clip_offset(&self, mut offset: usize, bias: Bias) -> usize { let mut cursor = self.chunks.cursor::(); - cursor.seek(&offset, SeekBias::Left, &()); + cursor.seek(&offset, Bias::Left, &()); if let Some(chunk) = cursor.item() { let mut ix = offset - cursor.start(); while !chunk.0.is_char_boundary(ix) { @@ -170,7 +170,7 @@ impl Rope { pub fn clip_point(&self, point: Point, bias: Bias) -> Point { let mut cursor = self.chunks.cursor::(); - cursor.seek(&point, SeekBias::Right, &()); + cursor.seek(&point, Bias::Right, &()); if let Some(chunk) = cursor.item() { let overshoot = point - cursor.start(); *cursor.start() + chunk.clip_point(overshoot, bias) @@ -197,7 +197,7 @@ pub struct Cursor<'a> { impl<'a> Cursor<'a> { pub fn new(rope: &'a Rope, offset: usize) -> Self { let mut chunks = rope.chunks.cursor(); - chunks.seek(&offset, SeekBias::Right, &()); + chunks.seek(&offset, Bias::Right, &()); Self { rope, chunks, @@ -208,24 +208,29 @@ impl<'a> Cursor<'a> { pub fn seek_forward(&mut self, end_offset: usize) { debug_assert!(end_offset >= self.offset); - self.chunks.seek_forward(&end_offset, SeekBias::Right, &()); + self.chunks.seek_forward(&end_offset, Bias::Right, &()); self.offset = end_offset; } pub fn slice(&mut self, end_offset: usize) -> Rope { - debug_assert!(end_offset >= self.offset); + debug_assert!( + end_offset >= self.offset, + "cannot slice backwards from {} to {}", + self.offset, + end_offset + ); let mut slice = Rope::new(); if let Some(start_chunk) = self.chunks.item() { let start_ix = self.offset - self.chunks.start(); - let end_ix = cmp::min(end_offset, self.chunks.end()) - self.chunks.start(); + let end_ix = cmp::min(end_offset, self.chunks.end(&())) - self.chunks.start(); slice.push(&start_chunk.0[start_ix..end_ix]); } - if end_offset > self.chunks.end() { - self.chunks.next(); + if end_offset > self.chunks.end(&()) { + self.chunks.next(&()); slice.append(Rope { - chunks: self.chunks.slice(&end_offset, SeekBias::Right, &()), + chunks: self.chunks.slice(&end_offset, Bias::Right, &()), }); if let Some(end_chunk) = self.chunks.item() { let end_ix = end_offset - self.chunks.start(); @@ -243,13 +248,13 @@ impl<'a> Cursor<'a> { let mut summary = TextSummary::default(); if let Some(start_chunk) = self.chunks.item() { let start_ix = self.offset - self.chunks.start(); - let end_ix = cmp::min(end_offset, self.chunks.end()) - self.chunks.start(); + let end_ix = cmp::min(end_offset, self.chunks.end(&())) - self.chunks.start(); summary = TextSummary::from(&start_chunk.0[start_ix..end_ix]); } - if end_offset > self.chunks.end() { - self.chunks.next(); - summary += &self.chunks.summary(&end_offset, SeekBias::Right, &()); + if end_offset > self.chunks.end(&()) { + self.chunks.next(&()); + summary += &self.chunks.summary(&end_offset, Bias::Right, &()); if let Some(end_chunk) = self.chunks.item() { let end_ix = end_offset - self.chunks.start(); summary += TextSummary::from(&end_chunk.0[..end_ix]); @@ -260,7 +265,7 @@ impl<'a> Cursor<'a> { } pub fn suffix(mut self) -> Rope { - self.slice(self.rope.chunks.extent()) + self.slice(self.rope.chunks.extent(&())) } pub fn offset(&self) -> usize { @@ -276,7 +281,7 @@ pub struct Chunks<'a> { impl<'a> Chunks<'a> { pub fn new(rope: &'a Rope, range: Range) -> Self { let mut chunks = rope.chunks.cursor(); - chunks.seek(&range.start, SeekBias::Right, &()); + chunks.seek(&range.start, Bias::Right, &()); Self { chunks, range } } @@ -285,10 +290,10 @@ impl<'a> Chunks<'a> { } pub fn seek(&mut self, offset: usize) { - if offset >= self.chunks.end() { - self.chunks.seek_forward(&offset, SeekBias::Right, &()); + if offset >= self.chunks.end(&()) { + self.chunks.seek_forward(&offset, Bias::Right, &()); } else { - self.chunks.seek(&offset, SeekBias::Right, &()); + self.chunks.seek(&offset, Bias::Right, &()); } self.range.start = offset; } @@ -312,7 +317,7 @@ impl<'a> Iterator for Chunks<'a> { fn next(&mut self) -> Option { let result = self.peek(); if result.is_some() { - self.chunks.next(); + self.chunks.next(&()); } result } @@ -478,19 +483,19 @@ impl std::ops::AddAssign for TextSummary { } impl<'a> sum_tree::Dimension<'a, TextSummary> for TextSummary { - fn add_summary(&mut self, summary: &'a TextSummary) { + fn add_summary(&mut self, summary: &'a TextSummary, _: &()) { *self += summary; } } impl<'a> sum_tree::Dimension<'a, TextSummary> for usize { - fn add_summary(&mut self, summary: &'a TextSummary) { + fn add_summary(&mut self, summary: &'a TextSummary, _: &()) { *self += summary.bytes; } } impl<'a> sum_tree::Dimension<'a, TextSummary> for Point { - fn add_summary(&mut self, summary: &'a TextSummary) { + fn add_summary(&mut self, summary: &'a TextSummary, _: &()) { *self += &summary.lines; } } diff --git a/zed/src/editor/display_map/fold_map.rs b/zed/src/editor/display_map/fold_map.rs index 6fc3c7175b..39b7b91b13 100644 --- a/zed/src/editor/display_map/fold_map.rs +++ b/zed/src/editor/display_map/fold_map.rs @@ -1,17 +1,19 @@ use super::{ buffer::{AnchorRangeExt, TextSummary}, - Anchor, Bias, Buffer, DisplayPoint, Edit, Point, ToOffset, + Anchor, Buffer, DisplayPoint, Edit, Point, ToOffset, }; use crate::{ editor::buffer, settings::StyleId, - sum_tree::{self, Cursor, FilterCursor, SeekBias, SumTree}, + sum_tree::{self, Cursor, FilterCursor, SumTree}, time, + util::Bias, }; use gpui::{AppContext, ModelHandle}; use parking_lot::{Mutex, MutexGuard}; use std::{ cmp::{self, Ordering}, + iter, ops::Range, }; @@ -80,7 +82,13 @@ impl FoldMap { where T: ToOffset, { - self.intersecting_folds(range, cx).map(|f| &f.0) + let buffer = self.buffer.read(cx); + let mut folds = self.intersecting_folds(range, cx); + iter::from_fn(move || { + let item = folds.item().map(|f| &f.0); + folds.next(buffer); + item + }) } pub fn fold( @@ -118,7 +126,7 @@ impl FoldMap { let mut new_tree = SumTree::new(); let mut cursor = self.folds.cursor::<_, ()>(); for fold in folds { - new_tree.push_tree(cursor.slice(&fold, SeekBias::Right, buffer), buffer); + new_tree.push_tree(cursor.slice(&fold, Bias::Right, buffer), buffer); new_tree.push(fold, buffer); } new_tree.push_tree(cursor.suffix(buffer), buffer); @@ -149,7 +157,7 @@ impl FoldMap { ..Default::default() }); fold_ixs_to_delete.push(*folds_cursor.start()); - folds_cursor.next(); + folds_cursor.next(buffer); } } @@ -166,8 +174,8 @@ impl FoldMap { let mut cursor = self.folds.cursor::<_, ()>(); let mut folds = SumTree::new(); for fold_ix in fold_ixs_to_delete { - folds.push_tree(cursor.slice(&fold_ix, SeekBias::Right, buffer), buffer); - cursor.next(); + folds.push_tree(cursor.slice(&fold_ix, Bias::Right, buffer), buffer); + cursor.next(buffer); } folds.push_tree(cursor.suffix(buffer), buffer); folds @@ -186,10 +194,13 @@ impl FoldMap { let buffer = self.buffer.read(cx); let start = buffer.anchor_before(range.start.to_offset(buffer)); let end = buffer.anchor_after(range.end.to_offset(buffer)); - self.folds.filter::<_, usize>(move |summary| { - start.cmp(&summary.max_end, buffer).unwrap() == Ordering::Less - && end.cmp(&summary.min_start, buffer).unwrap() == Ordering::Greater - }) + self.folds.filter::<_, usize>( + move |summary| { + start.cmp(&summary.max_end, buffer).unwrap() == Ordering::Less + && end.cmp(&summary.min_start, buffer).unwrap() == Ordering::Greater + }, + buffer, + ) } pub fn intersects_fold(&self, offset: T, cx: &AppContext) -> bool @@ -200,20 +211,20 @@ impl FoldMap { let offset = offset.to_offset(buffer); let transforms = self.sync(cx); let mut cursor = transforms.cursor::(); - cursor.seek(&offset, SeekBias::Right, &()); + cursor.seek(&offset, Bias::Right, &()); cursor.item().map_or(false, |t| t.display_text.is_some()) } pub fn is_line_folded(&self, display_row: u32, cx: &AppContext) -> bool { let transforms = self.sync(cx); let mut cursor = transforms.cursor::(); - cursor.seek(&DisplayPoint::new(display_row, 0), SeekBias::Right, &()); + cursor.seek(&DisplayPoint::new(display_row, 0), Bias::Right, &()); while let Some(transform) = cursor.item() { if transform.display_text.is_some() { return true; } - if cursor.end().row() == display_row { - cursor.next() + if cursor.end(&()).row() == display_row { + cursor.next(&()) } else { break; } @@ -232,7 +243,7 @@ impl FoldMap { pub fn to_buffer_point(&self, display_point: DisplayPoint, cx: &AppContext) -> Point { let transforms = self.sync(cx); let mut cursor = transforms.cursor::(); - cursor.seek(&display_point, SeekBias::Right, &()); + cursor.seek(&display_point, Bias::Right, &()); let overshoot = display_point.0 - cursor.start().display.lines; cursor.start().buffer.lines + overshoot } @@ -240,11 +251,11 @@ impl FoldMap { pub fn to_display_point(&self, point: Point, cx: &AppContext) -> DisplayPoint { let transforms = self.sync(cx); let mut cursor = transforms.cursor::(); - cursor.seek(&point, SeekBias::Right, &()); + cursor.seek(&point, Bias::Right, &()); let overshoot = point - cursor.start().buffer.lines; DisplayPoint(cmp::min( cursor.start().display.lines + overshoot, - cursor.end().display.lines, + cursor.end(&()).display.lines, )) } @@ -265,18 +276,15 @@ impl FoldMap { let mut new_transforms = SumTree::new(); let mut transforms = self.transforms.lock(); let mut cursor = transforms.cursor::(); - cursor.seek(&0, SeekBias::Right, &()); + cursor.seek(&0, Bias::Right, &()); while let Some(mut edit) = edits.next() { - new_transforms.push_tree( - cursor.slice(&edit.old_range.start, SeekBias::Left, &()), - &(), - ); + new_transforms.push_tree(cursor.slice(&edit.old_range.start, Bias::Left, &()), &()); edit.new_range.start -= edit.old_range.start - cursor.start(); edit.old_range.start = *cursor.start(); - cursor.seek(&edit.old_range.end, SeekBias::Right, &()); - cursor.next(); + cursor.seek(&edit.old_range.end, Bias::Right, &()); + cursor.next(&()); let mut delta = edit.delta(); loop { @@ -292,8 +300,8 @@ impl FoldMap { if next_edit.old_range.end >= edit.old_range.end { edit.old_range.end = next_edit.old_range.end; - cursor.seek(&edit.old_range.end, SeekBias::Right, &()); - cursor.next(); + cursor.seek(&edit.old_range.end, Bias::Right, &()); + cursor.next(&()); } } else { break; @@ -305,10 +313,15 @@ impl FoldMap { let anchor = buffer.anchor_before(edit.new_range.start); let mut folds_cursor = self.folds.cursor::<_, ()>(); - folds_cursor.seek(&Fold(anchor..Anchor::End), SeekBias::Left, buffer); - let mut folds = folds_cursor - .map(|f| f.0.start.to_offset(buffer)..f.0.end.to_offset(buffer)) - .peekable(); + folds_cursor.seek(&Fold(anchor..Anchor::End), Bias::Left, buffer); + let mut folds = iter::from_fn(move || { + let item = folds_cursor + .item() + .map(|f| f.0.start.to_offset(buffer)..f.0.end.to_offset(buffer)); + folds_cursor.next(buffer); + item + }) + .peekable(); while folds .peek() @@ -417,7 +430,7 @@ impl FoldMapSnapshot { let display_point = Point::new(start_row, 0); let mut cursor = self.transforms.cursor(); - cursor.seek(&DisplayPoint(display_point), SeekBias::Left, &()); + cursor.seek(&DisplayPoint(display_point), Bias::Left, &()); BufferRows { display_point, @@ -431,7 +444,7 @@ impl FoldMapSnapshot { pub fn chunks_at(&self, offset: DisplayOffset) -> Chunks { let mut transform_cursor = self.transforms.cursor::(); - transform_cursor.seek(&offset, SeekBias::Right, &()); + transform_cursor.seek(&offset, Bias::Right, &()); let overshoot = offset.0 - transform_cursor.start().display.bytes; let buffer_offset = transform_cursor.start().buffer.bytes + overshoot; Chunks { @@ -444,11 +457,11 @@ impl FoldMapSnapshot { pub fn highlighted_chunks(&mut self, range: Range) -> HighlightedChunks { let mut transform_cursor = self.transforms.cursor::(); - transform_cursor.seek(&range.end, SeekBias::Right, &()); + transform_cursor.seek(&range.end, Bias::Right, &()); let overshoot = range.end.0 - transform_cursor.start().display.bytes; let buffer_end = transform_cursor.start().buffer.bytes + overshoot; - transform_cursor.seek(&range.start, SeekBias::Right, &()); + transform_cursor.seek(&range.start, Bias::Right, &()); let overshoot = range.start.0 - transform_cursor.start().display.bytes; let buffer_start = transform_cursor.start().buffer.bytes + overshoot; @@ -469,7 +482,7 @@ impl FoldMapSnapshot { pub fn to_display_offset(&self, point: DisplayPoint) -> DisplayOffset { let mut cursor = self.transforms.cursor::(); - cursor.seek(&point, SeekBias::Right, &()); + cursor.seek(&point, Bias::Right, &()); let overshoot = point.0 - cursor.start().display.lines; let mut offset = cursor.start().display.bytes; if !overshoot.is_zero() { @@ -485,7 +498,7 @@ impl FoldMapSnapshot { pub fn to_buffer_offset(&self, point: DisplayPoint) -> usize { let mut cursor = self.transforms.cursor::(); - cursor.seek(&point, SeekBias::Right, &()); + cursor.seek(&point, Bias::Right, &()); let overshoot = point.0 - cursor.start().display.lines; self.buffer .to_offset(cursor.start().buffer.lines + overshoot) @@ -494,14 +507,14 @@ impl FoldMapSnapshot { #[cfg(test)] pub fn clip_offset(&self, offset: DisplayOffset, bias: Bias) -> DisplayOffset { let mut cursor = self.transforms.cursor::(); - cursor.seek(&offset, SeekBias::Right, &()); + cursor.seek(&offset, Bias::Right, &()); if let Some(transform) = cursor.item() { let transform_start = cursor.start().display.bytes; if transform.display_text.is_some() { if offset.0 == transform_start || matches!(bias, Bias::Left) { DisplayOffset(transform_start) } else { - DisplayOffset(cursor.end().display.bytes) + DisplayOffset(cursor.end(&()).display.bytes) } } else { let overshoot = offset.0 - transform_start; @@ -519,14 +532,14 @@ impl FoldMapSnapshot { pub fn clip_point(&self, point: DisplayPoint, bias: Bias) -> DisplayPoint { let mut cursor = self.transforms.cursor::(); - cursor.seek(&point, SeekBias::Right, &()); + cursor.seek(&point, Bias::Right, &()); if let Some(transform) = cursor.item() { let transform_start = cursor.start().display.lines; if transform.display_text.is_some() { if point.0 == transform_start || matches!(bias, Bias::Left) { DisplayPoint(transform_start) } else { - DisplayPoint(cursor.end().display.lines) + DisplayPoint(cursor.end(&()).display.lines) } } else { let overshoot = point.0 - transform_start; @@ -574,7 +587,7 @@ impl sum_tree::Summary for TransformSummary { } impl<'a> sum_tree::Dimension<'a, TransformSummary> for TransformSummary { - fn add_summary(&mut self, summary: &'a TransformSummary) { + fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) { sum_tree::Summary::add_summary(self, summary, &()); } } @@ -649,7 +662,7 @@ impl sum_tree::Summary for FoldSummary { } impl<'a> sum_tree::Dimension<'a, FoldSummary> for Fold { - fn add_summary(&mut self, summary: &'a FoldSummary) { + fn add_summary(&mut self, summary: &'a FoldSummary, _: &Buffer) { self.0.start = summary.start.clone(); self.0.end = summary.end.clone(); } @@ -662,7 +675,7 @@ impl<'a> sum_tree::SeekDimension<'a, FoldSummary> for Fold { } impl<'a> sum_tree::Dimension<'a, FoldSummary> for usize { - fn add_summary(&mut self, summary: &'a FoldSummary) { + fn add_summary(&mut self, summary: &'a FoldSummary, _: &Buffer) { *self += summary.count; } } @@ -676,8 +689,8 @@ impl<'a> Iterator for BufferRows<'a> { type Item = u32; fn next(&mut self) -> Option { - while self.display_point > self.cursor.end().display.lines { - self.cursor.next(); + while self.display_point > self.cursor.end(&()).display.lines { + self.cursor.next(&()); if self.cursor.item().is_none() { // TODO: Return a bool from next? break; @@ -717,10 +730,10 @@ impl<'a> Iterator for Chunks<'a> { self.buffer_offset += transform.summary.buffer.bytes; self.buffer_chunks.seek(self.buffer_offset); - while self.buffer_offset >= self.transform_cursor.end().buffer.bytes + while self.buffer_offset >= self.transform_cursor.end(&()).buffer.bytes && self.transform_cursor.item().is_some() { - self.transform_cursor.next(); + self.transform_cursor.next(&()); } return Some(display_text); @@ -732,10 +745,10 @@ impl<'a> Iterator for Chunks<'a> { chunk = &chunk[offset_in_chunk..]; // Truncate the chunk so that it ends at the next fold. - let region_end = self.transform_cursor.end().buffer.bytes - self.buffer_offset; + let region_end = self.transform_cursor.end(&()).buffer.bytes - self.buffer_offset; if chunk.len() >= region_end { chunk = &chunk[0..region_end]; - self.transform_cursor.next(); + self.transform_cursor.next(&()); } else { self.buffer_chunks.next(); } @@ -772,10 +785,10 @@ impl<'a> Iterator for HighlightedChunks<'a> { self.buffer_offset += transform.summary.buffer.bytes; self.buffer_chunks.seek(self.buffer_offset); - while self.buffer_offset >= self.transform_cursor.end().buffer.bytes + while self.buffer_offset >= self.transform_cursor.end(&()).buffer.bytes && self.transform_cursor.item().is_some() { - self.transform_cursor.next(); + self.transform_cursor.next(&()); } return Some((display_text, StyleId::default())); @@ -796,10 +809,10 @@ impl<'a> Iterator for HighlightedChunks<'a> { chunk = &chunk[offset_in_chunk..]; // Truncate the chunk so that it ends at the next fold. - let region_end = self.transform_cursor.end().buffer.bytes - self.buffer_offset; + let region_end = self.transform_cursor.end(&()).buffer.bytes - self.buffer_offset; if chunk.len() >= region_end { chunk = &chunk[0..region_end]; - self.transform_cursor.next(); + self.transform_cursor.next(&()); } else { self.buffer_chunk.take(); } @@ -813,7 +826,7 @@ impl<'a> Iterator for HighlightedChunks<'a> { } impl<'a> sum_tree::Dimension<'a, TransformSummary> for DisplayPoint { - fn add_summary(&mut self, summary: &'a TransformSummary) { + fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) { self.0 += &summary.display.lines; } } @@ -822,19 +835,19 @@ impl<'a> sum_tree::Dimension<'a, TransformSummary> for DisplayPoint { pub struct DisplayOffset(usize); impl<'a> sum_tree::Dimension<'a, TransformSummary> for DisplayOffset { - fn add_summary(&mut self, summary: &'a TransformSummary) { + fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) { self.0 += &summary.display.bytes; } } impl<'a> sum_tree::Dimension<'a, TransformSummary> for Point { - fn add_summary(&mut self, summary: &'a TransformSummary) { + fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) { *self += &summary.buffer.lines; } } impl<'a> sum_tree::Dimension<'a, TransformSummary> for usize { - fn add_summary(&mut self, summary: &'a TransformSummary) { + fn add_summary(&mut self, summary: &'a TransformSummary, _: &()) { *self += &summary.buffer.bytes; } } @@ -1031,7 +1044,7 @@ mod tests { 0..=34 => { let buffer = buffer.read(cx); let mut to_fold = Vec::new(); - for _ in 0..rng.gen_range(1..=5) { + for _ in 0..rng.gen_range(1..=2) { let end = buffer.clip_offset(rng.gen_range(0..=buffer.len()), Right); let start = buffer.clip_offset(rng.gen_range(0..=end), Left); to_fold.push(start..end); @@ -1172,7 +1185,7 @@ mod tests { let start = buffer.clip_offset(rng.gen_range(0..=end), Left); let expected_folds = map .folds - .items() + .items(buffer) .into_iter() .filter(|fold| { let start = buffer.anchor_before(start); @@ -1227,7 +1240,7 @@ mod tests { fn merged_fold_ranges(&self, cx: &AppContext) -> Vec> { let buffer = self.buffer.read(cx); - let mut folds = self.folds.items(); + let mut folds = self.folds.items(buffer); // Ensure sorting doesn't change how folds get merged and displayed. folds.sort_by(|a, b| a.0.cmp(&b.0, buffer).unwrap()); let mut fold_ranges = folds diff --git a/zed/src/operation_queue.rs b/zed/src/operation_queue.rs index 2c0e234fe9..681d135870 100644 --- a/zed/src/operation_queue.rs +++ b/zed/src/operation_queue.rs @@ -89,7 +89,7 @@ impl<'a> Add<&'a Self> for OperationSummary { } impl<'a> Dimension<'a, OperationSummary> for OperationKey { - fn add_summary(&mut self, summary: &OperationSummary) { + fn add_summary(&mut self, summary: &OperationSummary, _: &()) { assert!(*self <= summary.key); *self = summary.key; } diff --git a/zed/src/sum_tree.rs b/zed/src/sum_tree.rs index 8a2f9eb475..e307d2668b 100644 --- a/zed/src/sum_tree.rs +++ b/zed/src/sum_tree.rs @@ -1,5 +1,6 @@ mod cursor; +use crate::util::Bias; use arrayvec::ArrayVec; pub use cursor::Cursor; pub use cursor::FilterCursor; @@ -29,11 +30,23 @@ pub trait Summary: Default + Clone + fmt::Debug { } pub trait Dimension<'a, S: Summary>: Clone + fmt::Debug + Default { - fn add_summary(&mut self, _summary: &'a S); + fn add_summary(&mut self, _summary: &'a S, _: &S::Context); } impl<'a, T: Summary> Dimension<'a, T> for () { - fn add_summary(&mut self, _: &'a T) {} + fn add_summary(&mut self, _: &'a T, _: &T::Context) {} +} + +impl<'a, S, D1, D2> Dimension<'a, S> for (D1, D2) +where + S: Summary, + D1: Dimension<'a, S>, + D2: Dimension<'a, S>, +{ + fn add_summary(&mut self, summary: &'a S, cx: &S::Context) { + self.0.add_summary(summary, cx); + self.1.add_summary(summary, cx); + } } pub trait SeekDimension<'a, T: Summary>: Dimension<'a, T> { @@ -46,12 +59,6 @@ impl<'a, S: Summary, T: Dimension<'a, S> + Ord> SeekDimension<'a, S> for T { } } -#[derive(Copy, Clone, Eq, PartialEq)] -pub enum SeekBias { - Left, - Right, -} - #[derive(Debug, Clone)] pub struct SumTree(Arc>); @@ -71,9 +78,15 @@ impl SumTree { } #[allow(unused)] - pub fn items(&self) -> Vec { + pub fn items(&self, cx: &::Context) -> Vec { + let mut items = Vec::new(); let mut cursor = self.cursor::<(), ()>(); - cursor.cloned().collect() + cursor.next(cx); + while let Some(item) = cursor.item() { + items.push(item.clone()); + cursor.next(cx); + } + items } pub fn cursor<'a, S, U>(&'a self) -> Cursor @@ -84,12 +97,16 @@ impl SumTree { Cursor::new(self) } - pub fn filter<'a, F, U>(&'a self, filter_node: F) -> FilterCursor + pub fn filter<'a, F, U>( + &'a self, + filter_node: F, + cx: &::Context, + ) -> FilterCursor where F: Fn(&T::Summary) -> bool, U: Dimension<'a, T::Summary>, { - FilterCursor::new(self, filter_node) + FilterCursor::new(self, filter_node, cx) } #[allow(dead_code)] @@ -141,11 +158,14 @@ impl SumTree { } } - pub fn extent<'a, D: Dimension<'a, T::Summary>>(&'a self) -> D { + pub fn extent<'a, D: Dimension<'a, T::Summary>>( + &'a self, + cx: &::Context, + ) -> D { let mut extent = D::default(); match self.0.as_ref() { Node::Internal { summary, .. } | Node::Leaf { summary, .. } => { - extent.add_summary(summary); + extent.add_summary(summary, cx); } } extent @@ -392,7 +412,7 @@ impl SumTree { pub fn insert(&mut self, item: T, cx: &::Context) { *self = { let mut cursor = self.cursor::(); - let mut new_tree = cursor.slice(&item.key(), SeekBias::Left, cx); + let mut new_tree = cursor.slice(&item.key(), Bias::Left, cx); new_tree.push(item, cx); new_tree.push_tree(cursor.suffix(cx), cx); new_tree @@ -416,7 +436,7 @@ impl SumTree { let mut new_tree = SumTree::new(); let mut buffered_items = Vec::new(); - cursor.seek(&T::Key::default(), SeekBias::Left, cx); + cursor.seek(&T::Key::default(), Bias::Left, cx); for edit in edits { let new_key = edit.key(); let mut old_item = cursor.item(); @@ -426,7 +446,7 @@ impl SumTree { .map_or(false, |old_item| old_item.key() < new_key) { new_tree.extend(buffered_items.drain(..), cx); - let slice = cursor.slice(&new_key, SeekBias::Left, cx); + let slice = cursor.slice(&new_key, Bias::Left, cx); new_tree.push_tree(slice, cx); old_item = cursor.item(); } @@ -434,7 +454,7 @@ impl SumTree { if let Some(old_item) = old_item { if old_item.key() == new_key { removed.push(old_item.clone()); - cursor.next(); + cursor.next(cx); } } @@ -456,7 +476,7 @@ impl SumTree { pub fn get(&self, key: &T::Key, cx: &::Context) -> Option<&T> { let mut cursor = self.cursor::(); - if cursor.seek(key, SeekBias::Left, cx) { + if cursor.seek(key, Bias::Left, cx) { cursor.item() } else { None @@ -580,7 +600,10 @@ mod tests { tree2.extend(50..100, &()); tree1.push_tree(tree2, &()); - assert_eq!(tree1.items(), (0..20).chain(50..100).collect::>()); + assert_eq!( + tree1.items(&()), + (0..20).chain(50..100).collect::>() + ); } #[test] @@ -596,32 +619,33 @@ mod tests { tree.extend(rng.sample_iter(distributions::Standard).take(count), &()); for _ in 0..5 { - let splice_end = rng.gen_range(0..tree.extent::().0 + 1); + let splice_end = rng.gen_range(0..tree.extent::(&()).0 + 1); let splice_start = rng.gen_range(0..splice_end + 1); let count = rng.gen_range(0..3); - let tree_end = tree.extent::(); + let tree_end = tree.extent::(&()); let new_items = rng .sample_iter(distributions::Standard) .take(count) .collect::>(); - let mut reference_items = tree.items(); + let mut reference_items = tree.items(&()); reference_items.splice(splice_start..splice_end, new_items.clone()); tree = { let mut cursor = tree.cursor::(); - let mut new_tree = cursor.slice(&Count(splice_start), SeekBias::Right, &()); + let mut new_tree = cursor.slice(&Count(splice_start), Bias::Right, &()); new_tree.extend(new_items, &()); - cursor.seek(&Count(splice_end), SeekBias::Right, &()); - new_tree.push_tree(cursor.slice(&tree_end, SeekBias::Right, &()), &()); + cursor.seek(&Count(splice_end), Bias::Right, &()); + new_tree.push_tree(cursor.slice(&tree_end, Bias::Right, &()), &()); new_tree }; - assert_eq!(tree.items(), reference_items); + assert_eq!(tree.items(&()), reference_items); - let mut filter_cursor = tree.filter::<_, Count>(|summary| summary.contains_even); + let mut filter_cursor = + tree.filter::<_, Count>(|summary| summary.contains_even, &()); let mut reference_filter = tree - .items() + .items(&()) .into_iter() .enumerate() .filter(|(_, item)| (item & 1) == 0); @@ -629,14 +653,14 @@ mod tests { let (reference_index, reference_item) = reference_filter.next().unwrap(); assert_eq!(actual_item, &reference_item); assert_eq!(filter_cursor.start().0, reference_index); - filter_cursor.next(); + filter_cursor.next(&()); } assert!(reference_filter.next().is_none()); - let mut pos = rng.gen_range(0..tree.extent::().0 + 1); + let mut pos = rng.gen_range(0..tree.extent::(&()).0 + 1); let mut before_start = false; let mut cursor = tree.cursor::(); - cursor.seek(&Count(pos), SeekBias::Right, &()); + cursor.seek(&Count(pos), Bias::Right, &()); for i in 0..10 { assert_eq!(cursor.start().0, pos); @@ -654,13 +678,13 @@ mod tests { } if i < 5 { - cursor.next(); + cursor.next(&()); if pos < reference_items.len() { pos += 1; before_start = false; } } else { - cursor.prev(); + cursor.prev(&()); if pos == 0 { before_start = true; } @@ -670,18 +694,10 @@ mod tests { } for _ in 0..10 { - let end = rng.gen_range(0..tree.extent::().0 + 1); + let end = rng.gen_range(0..tree.extent::(&()).0 + 1); let start = rng.gen_range(0..end + 1); - let start_bias = if rng.gen() { - SeekBias::Left - } else { - SeekBias::Right - }; - let end_bias = if rng.gen() { - SeekBias::Left - } else { - SeekBias::Right - }; + let start_bias = if rng.gen() { Bias::Left } else { Bias::Right }; + let end_bias = if rng.gen() { Bias::Left } else { Bias::Right }; let mut cursor = tree.cursor::(); cursor.seek(&Count(start), start_bias, &()); @@ -701,7 +717,7 @@ mod tests { let tree = SumTree::::new(); let mut cursor = tree.cursor::(); assert_eq!( - cursor.slice(&Count(0), SeekBias::Right, &()).items(), + cursor.slice(&Count(0), Bias::Right, &()).items(&()), Vec::::new() ); assert_eq!(cursor.item(), None); @@ -713,34 +729,34 @@ mod tests { tree.extend(vec![1], &()); let mut cursor = tree.cursor::(); assert_eq!( - cursor.slice(&Count(0), SeekBias::Right, &()).items(), + cursor.slice(&Count(0), Bias::Right, &()).items(&()), Vec::::new() ); assert_eq!(cursor.item(), Some(&1)); assert_eq!(cursor.prev_item(), None); assert_eq!(cursor.start(), &Sum(0)); - cursor.next(); + cursor.next(&()); assert_eq!(cursor.item(), None); assert_eq!(cursor.prev_item(), Some(&1)); assert_eq!(cursor.start(), &Sum(1)); - cursor.prev(); + cursor.prev(&()); assert_eq!(cursor.item(), Some(&1)); assert_eq!(cursor.prev_item(), None); assert_eq!(cursor.start(), &Sum(0)); let mut cursor = tree.cursor::(); - assert_eq!(cursor.slice(&Count(1), SeekBias::Right, &()).items(), [1]); + assert_eq!(cursor.slice(&Count(1), Bias::Right, &()).items(&()), [1]); assert_eq!(cursor.item(), None); assert_eq!(cursor.prev_item(), Some(&1)); assert_eq!(cursor.start(), &Sum(1)); - cursor.seek(&Count(0), SeekBias::Right, &()); + cursor.seek(&Count(0), Bias::Right, &()); assert_eq!( cursor - .slice(&tree.extent::(), SeekBias::Right, &()) - .items(), + .slice(&tree.extent::(&()), Bias::Right, &()) + .items(&()), [1] ); assert_eq!(cursor.item(), None); @@ -752,71 +768,68 @@ mod tests { tree.extend(vec![1, 2, 3, 4, 5, 6], &()); let mut cursor = tree.cursor::(); - assert_eq!( - cursor.slice(&Count(2), SeekBias::Right, &()).items(), - [1, 2] - ); + assert_eq!(cursor.slice(&Count(2), Bias::Right, &()).items(&()), [1, 2]); assert_eq!(cursor.item(), Some(&3)); assert_eq!(cursor.prev_item(), Some(&2)); assert_eq!(cursor.start(), &Sum(3)); - cursor.next(); + cursor.next(&()); assert_eq!(cursor.item(), Some(&4)); assert_eq!(cursor.prev_item(), Some(&3)); assert_eq!(cursor.start(), &Sum(6)); - cursor.next(); + cursor.next(&()); assert_eq!(cursor.item(), Some(&5)); assert_eq!(cursor.prev_item(), Some(&4)); assert_eq!(cursor.start(), &Sum(10)); - cursor.next(); + cursor.next(&()); assert_eq!(cursor.item(), Some(&6)); assert_eq!(cursor.prev_item(), Some(&5)); assert_eq!(cursor.start(), &Sum(15)); - cursor.next(); - cursor.next(); + cursor.next(&()); + cursor.next(&()); assert_eq!(cursor.item(), None); assert_eq!(cursor.prev_item(), Some(&6)); assert_eq!(cursor.start(), &Sum(21)); - cursor.prev(); + cursor.prev(&()); assert_eq!(cursor.item(), Some(&6)); assert_eq!(cursor.prev_item(), Some(&5)); assert_eq!(cursor.start(), &Sum(15)); - cursor.prev(); + cursor.prev(&()); assert_eq!(cursor.item(), Some(&5)); assert_eq!(cursor.prev_item(), Some(&4)); assert_eq!(cursor.start(), &Sum(10)); - cursor.prev(); + cursor.prev(&()); assert_eq!(cursor.item(), Some(&4)); assert_eq!(cursor.prev_item(), Some(&3)); assert_eq!(cursor.start(), &Sum(6)); - cursor.prev(); + cursor.prev(&()); assert_eq!(cursor.item(), Some(&3)); assert_eq!(cursor.prev_item(), Some(&2)); assert_eq!(cursor.start(), &Sum(3)); - cursor.prev(); + cursor.prev(&()); assert_eq!(cursor.item(), Some(&2)); assert_eq!(cursor.prev_item(), Some(&1)); assert_eq!(cursor.start(), &Sum(1)); - cursor.prev(); + cursor.prev(&()); assert_eq!(cursor.item(), Some(&1)); assert_eq!(cursor.prev_item(), None); assert_eq!(cursor.start(), &Sum(0)); - cursor.prev(); + cursor.prev(&()); assert_eq!(cursor.item(), None); assert_eq!(cursor.prev_item(), None); assert_eq!(cursor.start(), &Sum(0)); - cursor.next(); + cursor.next(&()); assert_eq!(cursor.item(), Some(&1)); assert_eq!(cursor.prev_item(), None); assert_eq!(cursor.start(), &Sum(0)); @@ -824,19 +837,19 @@ mod tests { let mut cursor = tree.cursor::(); assert_eq!( cursor - .slice(&tree.extent::(), SeekBias::Right, &()) - .items(), - tree.items() + .slice(&tree.extent::(&()), Bias::Right, &()) + .items(&()), + tree.items(&()) ); assert_eq!(cursor.item(), None); assert_eq!(cursor.prev_item(), Some(&6)); assert_eq!(cursor.start(), &Sum(21)); - cursor.seek(&Count(3), SeekBias::Right, &()); + cursor.seek(&Count(3), Bias::Right, &()); assert_eq!( cursor - .slice(&tree.extent::(), SeekBias::Right, &()) - .items(), + .slice(&tree.extent::(&()), Bias::Right, &()) + .items(&()), [4, 5, 6] ); assert_eq!(cursor.item(), None); @@ -844,23 +857,23 @@ mod tests { assert_eq!(cursor.start(), &Sum(21)); // Seeking can bias left or right - cursor.seek(&Count(1), SeekBias::Left, &()); + cursor.seek(&Count(1), Bias::Left, &()); assert_eq!(cursor.item(), Some(&1)); - cursor.seek(&Count(1), SeekBias::Right, &()); + cursor.seek(&Count(1), Bias::Right, &()); assert_eq!(cursor.item(), Some(&2)); // Slicing without resetting starts from where the cursor is parked at. - cursor.seek(&Count(1), SeekBias::Right, &()); + cursor.seek(&Count(1), Bias::Right, &()); assert_eq!( - cursor.slice(&Count(3), SeekBias::Right, &()).items(), + cursor.slice(&Count(3), Bias::Right, &()).items(&()), vec![2, 3] ); assert_eq!( - cursor.slice(&Count(6), SeekBias::Left, &()).items(), + cursor.slice(&Count(6), Bias::Left, &()).items(&()), vec![4, 5] ); assert_eq!( - cursor.slice(&Count(6), SeekBias::Right, &()).items(), + cursor.slice(&Count(6), Bias::Right, &()).items(&()), vec![6] ); } @@ -870,7 +883,7 @@ mod tests { let mut tree = SumTree::::new(); let removed = tree.edit(vec![Edit::Insert(1), Edit::Insert(2), Edit::Insert(0)], &()); - assert_eq!(tree.items(), vec![0, 1, 2]); + assert_eq!(tree.items(&()), vec![0, 1, 2]); assert_eq!(removed, Vec::::new()); assert_eq!(tree.get(&0, &()), Some(&0)); assert_eq!(tree.get(&1, &()), Some(&1)); @@ -878,7 +891,7 @@ mod tests { assert_eq!(tree.get(&4, &()), None); let removed = tree.edit(vec![Edit::Insert(2), Edit::Insert(4), Edit::Remove(0)], &()); - assert_eq!(tree.items(), vec![1, 2, 4]); + assert_eq!(tree.items(&()), vec![1, 2, 4]); assert_eq!(removed, vec![0, 2]); assert_eq!(tree.get(&0, &()), None); assert_eq!(tree.get(&1, &()), Some(&1)); @@ -933,19 +946,19 @@ mod tests { } impl<'a> Dimension<'a, IntegersSummary> for u8 { - fn add_summary(&mut self, summary: &IntegersSummary) { + fn add_summary(&mut self, summary: &IntegersSummary, _: &()) { *self = summary.max; } } impl<'a> Dimension<'a, IntegersSummary> for Count { - fn add_summary(&mut self, summary: &IntegersSummary) { + fn add_summary(&mut self, summary: &IntegersSummary, _: &()) { self.0 += summary.count.0; } } impl<'a> Dimension<'a, IntegersSummary> for Sum { - fn add_summary(&mut self, summary: &IntegersSummary) { + fn add_summary(&mut self, summary: &IntegersSummary, _: &()) { self.0 += summary.sum.0; } } diff --git a/zed/src/sum_tree/cursor.rs b/zed/src/sum_tree/cursor.rs index 146683ec2c..8374546a20 100644 --- a/zed/src/sum_tree/cursor.rs +++ b/zed/src/sum_tree/cursor.rs @@ -49,10 +49,10 @@ where &self.sum_dimension } - pub fn end(&self) -> U { + pub fn end(&self, cx: &::Context) -> U { if let Some(item_summary) = self.item_summary() { let mut end = self.start().clone(); - end.add_summary(item_summary); + end.add_summary(item_summary, cx); end } else { self.start().clone() @@ -134,13 +134,13 @@ where } #[allow(unused)] - pub fn prev(&mut self) { + pub fn prev(&mut self, cx: &::Context) { assert!(self.did_seek, "Must seek before calling this method"); if self.at_end { self.seek_dimension = S::default(); self.sum_dimension = U::default(); - self.descend_to_last_item(self.tree); + self.descend_to_last_item(self.tree, cx); self.at_end = false; } else { while let Some(entry) = self.stack.pop() { @@ -167,8 +167,8 @@ where .. } => { for summary in &child_summaries[0..new_index] { - self.seek_dimension.add_summary(summary); - self.sum_dimension.add_summary(summary); + self.seek_dimension.add_summary(summary, cx); + self.sum_dimension.add_summary(summary, cx); } self.stack.push(StackEntry { tree: entry.tree, @@ -176,12 +176,12 @@ where seek_dimension: self.seek_dimension.clone(), sum_dimension: self.sum_dimension.clone(), }); - self.descend_to_last_item(&child_trees[new_index]); + self.descend_to_last_item(&child_trees[new_index], cx); } Node::Leaf { item_summaries, .. } => { for item_summary in &item_summaries[0..new_index] { - self.seek_dimension.add_summary(item_summary); - self.sum_dimension.add_summary(item_summary); + self.seek_dimension.add_summary(item_summary, cx); + self.sum_dimension.add_summary(item_summary, cx); } self.stack.push(StackEntry { tree: entry.tree, @@ -198,11 +198,11 @@ where } } - pub fn next(&mut self) { - self.next_internal(|_| true) + pub fn next(&mut self, cx: &::Context) { + self.next_internal(|_| true, cx) } - fn next_internal(&mut self, filter_node: F) + fn next_internal(&mut self, filter_node: F, cx: &::Context) where F: Fn(&T::Summary) -> bool, { @@ -229,9 +229,8 @@ where .. } => { if !descend { - let summary = &child_summaries[entry.index]; - entry.seek_dimension.add_summary(summary); - entry.sum_dimension.add_summary(summary); + entry.seek_dimension = self.seek_dimension.clone(); + entry.sum_dimension = self.sum_dimension.clone(); entry.index += 1; } @@ -240,8 +239,8 @@ where if filter_node(next_summary) { break; } else { - self.seek_dimension.add_summary(next_summary); - self.sum_dimension.add_summary(next_summary); + self.seek_dimension.add_summary(next_summary, cx); + self.sum_dimension.add_summary(next_summary, cx); } entry.index += 1; } @@ -251,10 +250,10 @@ where Node::Leaf { item_summaries, .. } => { if !descend { let item_summary = &item_summaries[entry.index]; - self.seek_dimension.add_summary(item_summary); - entry.seek_dimension.add_summary(item_summary); - self.sum_dimension.add_summary(item_summary); - entry.sum_dimension.add_summary(item_summary); + self.seek_dimension.add_summary(item_summary, cx); + entry.seek_dimension.add_summary(item_summary, cx); + self.sum_dimension.add_summary(item_summary, cx); + entry.sum_dimension.add_summary(item_summary, cx); entry.index += 1; } @@ -263,10 +262,10 @@ where if filter_node(next_item_summary) { return; } else { - self.seek_dimension.add_summary(next_item_summary); - entry.seek_dimension.add_summary(next_item_summary); - self.sum_dimension.add_summary(next_item_summary); - entry.sum_dimension.add_summary(next_item_summary); + self.seek_dimension.add_summary(next_item_summary, cx); + entry.seek_dimension.add_summary(next_item_summary, cx); + self.sum_dimension.add_summary(next_item_summary, cx); + entry.sum_dimension.add_summary(next_item_summary, cx); entry.index += 1; } } else { @@ -295,7 +294,11 @@ where debug_assert!(self.stack.is_empty() || self.stack.last().unwrap().tree.0.is_leaf()); } - fn descend_to_last_item(&mut self, mut subtree: &'a SumTree) { + fn descend_to_last_item( + &mut self, + mut subtree: &'a SumTree, + cx: &::Context, + ) { self.did_seek = true; loop { match subtree.0.as_ref() { @@ -305,8 +308,8 @@ where .. } => { for summary in &child_summaries[0..child_summaries.len() - 1] { - self.seek_dimension.add_summary(summary); - self.sum_dimension.add_summary(summary); + self.seek_dimension.add_summary(summary, cx); + self.sum_dimension.add_summary(summary, cx); } self.stack.push(StackEntry { @@ -320,8 +323,8 @@ where Node::Leaf { item_summaries, .. } => { let last_index = item_summaries.len().saturating_sub(1); for item_summary in &item_summaries[0..last_index] { - self.seek_dimension.add_summary(item_summary); - self.sum_dimension.add_summary(item_summary); + self.seek_dimension.add_summary(item_summary, cx); + self.sum_dimension.add_summary(item_summary, cx); } self.stack.push(StackEntry { tree: subtree, @@ -342,28 +345,28 @@ where S: SeekDimension<'a, T::Summary>, U: Dimension<'a, T::Summary>, { - pub fn seek(&mut self, pos: &S, bias: SeekBias, cx: &::Context) -> bool { + pub fn seek(&mut self, pos: &S, bias: Bias, cx: &::Context) -> bool { self.reset(); - self.seek_internal::<()>(pos, bias, &mut SeekAggregate::None, cx) + self.seek_internal::<()>(Some(pos), bias, &mut SeekAggregate::None, cx) } pub fn seek_forward( &mut self, pos: &S, - bias: SeekBias, + bias: Bias, cx: &::Context, ) -> bool { - self.seek_internal::<()>(pos, bias, &mut SeekAggregate::None, cx) + self.seek_internal::<()>(Some(pos), bias, &mut SeekAggregate::None, cx) } pub fn slice( &mut self, end: &S, - bias: SeekBias, + bias: Bias, cx: &::Context, ) -> SumTree { let mut slice = SeekAggregate::Slice(SumTree::new()); - self.seek_internal::<()>(end, bias, &mut slice, cx); + self.seek_internal::<()>(Some(end), bias, &mut slice, cx); if let SeekAggregate::Slice(slice) = slice { slice } else { @@ -372,9 +375,8 @@ where } pub fn suffix(&mut self, cx: &::Context) -> SumTree { - let extent = self.tree.extent::(); let mut slice = SeekAggregate::Slice(SumTree::new()); - self.seek_internal::<()>(&extent, SeekBias::Right, &mut slice, cx); + self.seek_internal::<()>(None, Bias::Right, &mut slice, cx); if let SeekAggregate::Slice(slice) = slice { slice } else { @@ -382,17 +384,12 @@ where } } - pub fn summary( - &mut self, - end: &S, - bias: SeekBias, - cx: &::Context, - ) -> D + pub fn summary(&mut self, end: &S, bias: Bias, cx: &::Context) -> D where D: Dimension<'a, T::Summary>, { let mut summary = SeekAggregate::Summary(D::default()); - self.seek_internal(end, bias, &mut summary, cx); + self.seek_internal(Some(end), bias, &mut summary, cx); if let SeekAggregate::Summary(summary) = summary { summary } else { @@ -402,229 +399,126 @@ where fn seek_internal( &mut self, - target: &S, - bias: SeekBias, + target: Option<&S>, + bias: Bias, aggregate: &mut SeekAggregate, cx: &::Context, ) -> bool where D: Dimension<'a, T::Summary>, { - debug_assert!(target.cmp(&self.seek_dimension, cx) >= Ordering::Equal); - let mut containing_subtree = None; + if let Some(target) = target { + debug_assert!( + target.cmp(&self.seek_dimension, cx) >= Ordering::Equal, + "cannot seek backward from {:?} to {:?}", + self.seek_dimension, + target + ); + } - if self.did_seek { - 'outer: while let Some(entry) = self.stack.last_mut() { - { - match *entry.tree.0 { - Node::Internal { - ref child_summaries, - ref child_trees, - .. - } => { + if !self.did_seek { + self.did_seek = true; + self.stack.push(StackEntry { + tree: self.tree, + index: 0, + seek_dimension: Default::default(), + sum_dimension: Default::default(), + }); + } + + let mut ascending = false; + 'outer: while let Some(entry) = self.stack.last_mut() { + match *entry.tree.0 { + Node::Internal { + ref child_summaries, + ref child_trees, + .. + } => { + if ascending { + entry.index += 1; + } + + for (child_tree, child_summary) in child_trees[entry.index..] + .iter() + .zip(&child_summaries[entry.index..]) + { + let mut child_end = self.seek_dimension.clone(); + child_end.add_summary(&child_summary, cx); + + let comparison = + target.map_or(Ordering::Greater, |t| t.cmp(&child_end, cx)); + if comparison == Ordering::Greater + || (comparison == Ordering::Equal && bias == Bias::Right) + { + self.seek_dimension = child_end; + self.sum_dimension.add_summary(child_summary, cx); + match aggregate { + SeekAggregate::None => {} + SeekAggregate::Slice(slice) => { + slice.push_tree(child_tree.clone(), cx); + } + SeekAggregate::Summary(summary) => { + summary.add_summary(child_summary, cx); + } + } entry.index += 1; - for (child_tree, child_summary) in child_trees[entry.index..] - .iter() - .zip(&child_summaries[entry.index..]) - { - let mut child_end = self.seek_dimension.clone(); - child_end.add_summary(&child_summary); - - let comparison = target.cmp(&child_end, cx); - if comparison == Ordering::Greater - || (comparison == Ordering::Equal && bias == SeekBias::Right) - { - self.seek_dimension = child_end; - self.sum_dimension.add_summary(child_summary); - match aggregate { - SeekAggregate::None => {} - SeekAggregate::Slice(slice) => { - slice.push_tree(child_tree.clone(), cx); - } - SeekAggregate::Summary(summary) => { - summary.add_summary(child_summary); - } - } - entry.index += 1; - } else { - containing_subtree = Some(child_tree); - break 'outer; - } - } - } - Node::Leaf { - ref items, - ref item_summaries, - .. - } => { - let mut slice_items = ArrayVec::<[T; 2 * TREE_BASE]>::new(); - let mut slice_item_summaries = - ArrayVec::<[T::Summary; 2 * TREE_BASE]>::new(); - let mut slice_items_summary = match aggregate { - SeekAggregate::Slice(_) => Some(T::Summary::default()), - _ => None, - }; - - for (item, item_summary) in items[entry.index..] - .iter() - .zip(&item_summaries[entry.index..]) - { - let mut child_end = self.seek_dimension.clone(); - child_end.add_summary(item_summary); - - let comparison = target.cmp(&child_end, cx); - if comparison == Ordering::Greater - || (comparison == Ordering::Equal && bias == SeekBias::Right) - { - self.seek_dimension = child_end; - self.sum_dimension.add_summary(item_summary); - match aggregate { - SeekAggregate::None => {} - SeekAggregate::Slice(_) => { - slice_items.push(item.clone()); - slice_item_summaries.push(item_summary.clone()); - slice_items_summary - .as_mut() - .unwrap() - .add_summary(item_summary, cx); - } - SeekAggregate::Summary(summary) => { - summary.add_summary(item_summary); - } - } - entry.index += 1; - } else { - if let SeekAggregate::Slice(slice) = aggregate { - slice.push_tree( - SumTree(Arc::new(Node::Leaf { - summary: slice_items_summary.unwrap(), - items: slice_items, - item_summaries: slice_item_summaries, - })), - cx, - ); - } - break 'outer; - } - } - - if let SeekAggregate::Slice(slice) = aggregate { - if !slice_items.is_empty() { - slice.push_tree( - SumTree(Arc::new(Node::Leaf { - summary: slice_items_summary.unwrap(), - items: slice_items, - item_summaries: slice_item_summaries, - })), - cx, - ); - } - } + entry.seek_dimension = self.seek_dimension.clone(); + entry.sum_dimension = self.sum_dimension.clone(); + } else { + self.stack.push(StackEntry { + tree: child_tree, + index: 0, + seek_dimension: self.seek_dimension.clone(), + sum_dimension: self.sum_dimension.clone(), + }); + ascending = false; + continue 'outer; } } } + Node::Leaf { + ref items, + ref item_summaries, + .. + } => { + let mut slice_items = ArrayVec::<[T; 2 * TREE_BASE]>::new(); + let mut slice_item_summaries = ArrayVec::<[T::Summary; 2 * TREE_BASE]>::new(); + let mut slice_items_summary = match aggregate { + SeekAggregate::Slice(_) => Some(T::Summary::default()), + _ => None, + }; - self.stack.pop(); - } - } else { - self.did_seek = true; - containing_subtree = Some(self.tree); - } + for (item, item_summary) in items[entry.index..] + .iter() + .zip(&item_summaries[entry.index..]) + { + let mut child_end = self.seek_dimension.clone(); + child_end.add_summary(item_summary, cx); - if let Some(mut subtree) = containing_subtree { - loop { - let mut next_subtree = None; - match *subtree.0 { - Node::Internal { - ref child_summaries, - ref child_trees, - .. - } => { - for (index, (child_tree, child_summary)) in - child_trees.iter().zip(child_summaries).enumerate() + let comparison = + target.map_or(Ordering::Greater, |t| t.cmp(&child_end, cx)); + if comparison == Ordering::Greater + || (comparison == Ordering::Equal && bias == Bias::Right) { - let mut child_end = self.seek_dimension.clone(); - child_end.add_summary(child_summary); - - let comparison = target.cmp(&child_end, cx); - if comparison == Ordering::Greater - || (comparison == Ordering::Equal && bias == SeekBias::Right) - { - self.seek_dimension = child_end; - self.sum_dimension.add_summary(child_summary); - match aggregate { - SeekAggregate::None => {} - SeekAggregate::Slice(slice) => { - slice.push_tree(child_trees[index].clone(), cx); - } - SeekAggregate::Summary(summary) => { - summary.add_summary(child_summary); - } + self.seek_dimension = child_end; + self.sum_dimension.add_summary(item_summary, cx); + match aggregate { + SeekAggregate::None => {} + SeekAggregate::Slice(_) => { + slice_items.push(item.clone()); + slice_item_summaries.push(item_summary.clone()); + slice_items_summary + .as_mut() + .unwrap() + .add_summary(item_summary, cx); } - } else { - self.stack.push(StackEntry { - tree: subtree, - index, - seek_dimension: self.seek_dimension.clone(), - sum_dimension: self.sum_dimension.clone(), - }); - next_subtree = Some(child_tree); - break; - } - } - } - Node::Leaf { - ref items, - ref item_summaries, - .. - } => { - let mut slice_items = ArrayVec::<[T; 2 * TREE_BASE]>::new(); - let mut slice_item_summaries = - ArrayVec::<[T::Summary; 2 * TREE_BASE]>::new(); - let mut slice_items_summary = match aggregate { - SeekAggregate::Slice(_) => Some(T::Summary::default()), - _ => None, - }; - - for (index, (item, item_summary)) in - items.iter().zip(item_summaries).enumerate() - { - let mut child_end = self.seek_dimension.clone(); - child_end.add_summary(item_summary); - - let comparison = target.cmp(&child_end, cx); - if comparison == Ordering::Greater - || (comparison == Ordering::Equal && bias == SeekBias::Right) - { - self.seek_dimension = child_end; - self.sum_dimension.add_summary(item_summary); - match aggregate { - SeekAggregate::None => {} - SeekAggregate::Slice(_) => { - slice_items.push(item.clone()); - slice_items_summary - .as_mut() - .unwrap() - .add_summary(item_summary, cx); - slice_item_summaries.push(item_summary.clone()); - } - SeekAggregate::Summary(summary) => { - summary.add_summary(item_summary); - } + SeekAggregate::Summary(summary) => { + summary.add_summary(item_summary, cx); } - } else { - self.stack.push(StackEntry { - tree: subtree, - index, - seek_dimension: self.seek_dimension.clone(), - sum_dimension: self.sum_dimension.clone(), - }); - break; } - } - - if let SeekAggregate::Slice(slice) = aggregate { - if !slice_items.is_empty() { + entry.index += 1; + } else { + if let SeekAggregate::Slice(slice) = aggregate { slice.push_tree( SumTree(Arc::new(Node::Leaf { summary: slice_items_summary.unwrap(), @@ -634,47 +528,59 @@ where cx, ); } + break 'outer; } } - }; - if let Some(next_subtree) = next_subtree { - subtree = next_subtree; - } else { - break; + if let SeekAggregate::Slice(slice) = aggregate { + if !slice_items.is_empty() { + slice.push_tree( + SumTree(Arc::new(Node::Leaf { + summary: slice_items_summary.unwrap(), + items: slice_items, + item_summaries: slice_item_summaries, + })), + cx, + ); + } + } } } + + self.stack.pop(); + ascending = true; } self.at_end = self.stack.is_empty(); debug_assert!(self.stack.is_empty() || self.stack.last().unwrap().tree.0.is_leaf()); - if bias == SeekBias::Left { - let mut end = self.seek_dimension.clone(); + + let mut end = self.seek_dimension.clone(); + if bias == Bias::Left { if let Some(summary) = self.item_summary() { - end.add_summary(summary); + end.add_summary(summary, cx); } - target.cmp(&end, cx) == Ordering::Equal - } else { - target.cmp(&self.seek_dimension, cx) == Ordering::Equal } + + target.map_or(false, |t| t.cmp(&end, cx) == Ordering::Equal) } } -impl<'a, T, S, U> Iterator for Cursor<'a, T, S, U> +impl<'a, T, S, Seek, Sum> Iterator for Cursor<'a, T, Seek, Sum> where - T: Item, - S: Dimension<'a, T::Summary>, - U: Dimension<'a, T::Summary>, + T: Item, + S: Summary, + Seek: Dimension<'a, T::Summary>, + Sum: Dimension<'a, T::Summary>, { type Item = &'a T; fn next(&mut self) -> Option { if !self.did_seek { - self.next(); + self.next(&()); } if let Some(item) = self.item() { - self.next(); + self.next(&()); Some(item) } else { None @@ -693,9 +599,13 @@ where T: Item, U: Dimension<'a, T::Summary>, { - pub fn new(tree: &'a SumTree, filter_node: F) -> Self { + pub fn new( + tree: &'a SumTree, + filter_node: F, + cx: &::Context, + ) -> Self { let mut cursor = tree.cursor::<(), U>(); - cursor.next_internal(&filter_node); + cursor.next_internal(&filter_node, cx); Self { cursor, filter_node, @@ -710,22 +620,23 @@ where self.cursor.item() } - pub fn next(&mut self) { - self.cursor.next_internal(&self.filter_node); + pub fn next(&mut self, cx: &::Context) { + self.cursor.next_internal(&self.filter_node, cx); } } -impl<'a, F, T, U> Iterator for FilterCursor<'a, F, T, U> +impl<'a, F, T, S, U> Iterator for FilterCursor<'a, F, T, U> where F: Fn(&T::Summary) -> bool, - T: Item, + T: Item, + S: Summary, U: Dimension<'a, T::Summary>, { type Item = &'a T; fn next(&mut self) -> Option { if let Some(item) = self.item() { - self.cursor.next_internal(&self.filter_node); + self.cursor.next_internal(&self.filter_node, &()); Some(item) } else { None diff --git a/zed/src/time.rs b/zed/src/time.rs index f1cf4eef91..00f4e54c18 100644 --- a/zed/src/time.rs +++ b/zed/src/time.rs @@ -1,20 +1,24 @@ use smallvec::SmallVec; -use std::cmp::{self, Ordering}; -use std::ops::{Add, AddAssign}; +use std::{ + cmp::{self, Ordering}, + fmt, + ops::{Add, AddAssign}, + slice, +}; pub type ReplicaId = u16; pub type Seq = u32; -#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq, Ord, PartialOrd)] +#[derive(Clone, Copy, Default, Eq, Hash, PartialEq, Ord, PartialOrd)] pub struct Local { pub replica_id: ReplicaId, pub value: Seq, } -#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[derive(Clone, Copy, Default, Eq, Hash, PartialEq)] pub struct Lamport { - pub value: Seq, pub replica_id: ReplicaId, + pub value: Seq, } impl Local { @@ -54,7 +58,7 @@ impl<'a> AddAssign<&'a Local> for Local { } } -#[derive(Clone, Debug, Default, Eq, PartialEq)] +#[derive(Clone, Default, Hash, Eq, PartialEq)] pub struct Global(SmallVec<[Local; 3]>); impl Global { @@ -81,12 +85,26 @@ impl Global { } } - pub fn observe_all(&mut self, other: &Self) { + pub fn join(&mut self, other: &Self) { for timestamp in other.0.iter() { self.observe(*timestamp); } } + pub fn meet(&mut self, other: &Self) { + for timestamp in other.0.iter() { + if let Some(entry) = self + .0 + .iter_mut() + .find(|t| t.replica_id == timestamp.replica_id) + { + entry.value = cmp::min(entry.value, timestamp.value); + } else { + self.0.push(*timestamp); + } + } + } + pub fn observed(&self, timestamp: Local) -> bool { self.get(timestamp.replica_id) >= timestamp.value } @@ -94,6 +112,10 @@ impl Global { pub fn changed_since(&self, other: &Self) -> bool { self.0.iter().any(|t| t.value > other.get(t.replica_id)) } + + pub fn iter(&self) -> slice::Iter { + self.0.iter() + } } impl PartialOrd for Global { @@ -117,6 +139,21 @@ impl PartialOrd for Global { } } +impl Ord for Lamport { + fn cmp(&self, other: &Self) -> Ordering { + // Use the replica id to break ties between concurrent events. + self.value + .cmp(&other.value) + .then_with(|| self.replica_id.cmp(&other.replica_id)) + } +} + +impl PartialOrd for Lamport { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + impl Lamport { pub fn new(replica_id: ReplicaId) -> Self { Self { @@ -135,3 +172,28 @@ impl Lamport { self.value = cmp::max(self.value, timestamp.value) + 1; } } + +impl fmt::Debug for Local { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Local {{{}: {}}}", self.replica_id, self.value) + } +} + +impl fmt::Debug for Lamport { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Lamport {{{}: {}}}", self.replica_id, self.value) + } +} + +impl fmt::Debug for Global { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Global {{")?; + for (i, element) in self.0.iter().enumerate() { + if i > 0 { + write!(f, ", ")?; + } + write!(f, "{}: {}", element.replica_id, element.value)?; + } + write!(f, "}}") + } +} diff --git a/zed/src/util.rs b/zed/src/util.rs index 6015ce7e0a..c744a47098 100644 --- a/zed/src/util.rs +++ b/zed/src/util.rs @@ -1,6 +1,29 @@ use rand::prelude::*; use std::cmp::Ordering; +#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash)] +pub enum Bias { + Left, + Right, +} + +impl PartialOrd for Bias { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for Bias { + fn cmp(&self, other: &Self) -> Ordering { + match (self, other) { + (Self::Left, Self::Left) => Ordering::Equal, + (Self::Left, Self::Right) => Ordering::Less, + (Self::Right, Self::Right) => Ordering::Equal, + (Self::Right, Self::Left) => Ordering::Greater, + } + } +} + pub fn post_inc(value: &mut usize) -> usize { let prev = *value; *value += 1; diff --git a/zed/src/worktree.rs b/zed/src/worktree.rs index f8bf316d54..762d98ee72 100644 --- a/zed/src/worktree.rs +++ b/zed/src/worktree.rs @@ -4,7 +4,8 @@ mod ignore; use crate::{ editor::{History, Rope}, - sum_tree::{self, Cursor, Edit, SeekBias, SumTree}, + sum_tree::{self, Cursor, Edit, SumTree}, + util::Bias, }; use ::ignore::gitignore::Gitignore; use anyhow::{Context, Result}; @@ -295,7 +296,7 @@ impl Snapshot { } let path = path.as_ref(); let mut cursor = self.entries.cursor::<_, ()>(); - if cursor.seek(&PathSearch::Exact(path), SeekBias::Left, &()) { + if cursor.seek(&PathSearch::Exact(path), Bias::Left, &()) { let entry = cursor.item().unwrap(); if entry.path.as_ref() == path { return matches!(entry.kind, EntryKind::PendingDir); @@ -310,7 +311,7 @@ impl Snapshot { fn entry_for_path(&self, path: impl AsRef) -> Option<&Entry> { let mut cursor = self.entries.cursor::<_, ()>(); - if cursor.seek(&PathSearch::Exact(path.as_ref()), SeekBias::Left, &()) { + if cursor.seek(&PathSearch::Exact(path.as_ref()), Bias::Left, &()) { cursor.item() } else { None @@ -367,8 +368,8 @@ impl Snapshot { fn remove_path(&mut self, path: &Path) { let new_entries = { let mut cursor = self.entries.cursor::<_, ()>(); - let mut new_entries = cursor.slice(&PathSearch::Exact(path), SeekBias::Left, &()); - cursor.seek_forward(&PathSearch::Successor(path), SeekBias::Left, &()); + let mut new_entries = cursor.slice(&PathSearch::Exact(path), Bias::Left, &()); + cursor.seek_forward(&PathSearch::Successor(path), Bias::Left, &()); new_entries.push_tree(cursor.suffix(&()), &()); new_entries }; @@ -603,7 +604,7 @@ impl Default for PathKey { } impl<'a> sum_tree::Dimension<'a, EntrySummary> for PathKey { - fn add_summary(&mut self, summary: &'a EntrySummary) { + fn add_summary(&mut self, summary: &'a EntrySummary, _: &()) { self.0 = summary.max_path.clone(); } } @@ -643,7 +644,7 @@ impl<'a> Default for PathSearch<'a> { } impl<'a: 'b, 'b> sum_tree::Dimension<'a, EntrySummary> for PathSearch<'b> { - fn add_summary(&mut self, summary: &'a EntrySummary) { + fn add_summary(&mut self, summary: &'a EntrySummary, _: &()) { *self = Self::Exact(summary.max_path.as_ref()); } } @@ -652,7 +653,7 @@ impl<'a: 'b, 'b> sum_tree::Dimension<'a, EntrySummary> for PathSearch<'b> { pub struct FileCount(usize); impl<'a> sum_tree::Dimension<'a, EntrySummary> for FileCount { - fn add_summary(&mut self, summary: &'a EntrySummary) { + fn add_summary(&mut self, summary: &'a EntrySummary, _: &()) { self.0 += summary.file_count; } } @@ -661,7 +662,7 @@ impl<'a> sum_tree::Dimension<'a, EntrySummary> for FileCount { pub struct VisibleFileCount(usize); impl<'a> sum_tree::Dimension<'a, EntrySummary> for VisibleFileCount { - fn add_summary(&mut self, summary: &'a EntrySummary) { + fn add_summary(&mut self, summary: &'a EntrySummary, _: &()) { self.0 += summary.visible_file_count; } } @@ -1296,13 +1297,13 @@ pub enum FileIter<'a> { impl<'a> FileIter<'a> { fn all(snapshot: &'a Snapshot, start: usize) -> Self { let mut cursor = snapshot.entries.cursor(); - cursor.seek(&FileCount(start), SeekBias::Right, &()); + cursor.seek(&FileCount(start), Bias::Right, &()); Self::All(cursor) } fn visible(snapshot: &'a Snapshot, start: usize) -> Self { let mut cursor = snapshot.entries.cursor(); - cursor.seek(&VisibleFileCount(start), SeekBias::Right, &()); + cursor.seek(&VisibleFileCount(start), Bias::Right, &()); Self::Visible(cursor) } @@ -1310,11 +1311,11 @@ impl<'a> FileIter<'a> { match self { Self::All(cursor) => { let ix = *cursor.start(); - cursor.seek_forward(&FileCount(ix.0 + 1), SeekBias::Right, &()); + cursor.seek_forward(&FileCount(ix.0 + 1), Bias::Right, &()); } Self::Visible(cursor) => { let ix = *cursor.start(); - cursor.seek_forward(&VisibleFileCount(ix.0 + 1), SeekBias::Right, &()); + cursor.seek_forward(&VisibleFileCount(ix.0 + 1), Bias::Right, &()); } } } @@ -1348,7 +1349,7 @@ struct ChildEntriesIter<'a> { impl<'a> ChildEntriesIter<'a> { fn new(parent_path: &'a Path, snapshot: &'a Snapshot) -> Self { let mut cursor = snapshot.entries.cursor(); - cursor.seek(&PathSearch::Exact(parent_path), SeekBias::Right, &()); + cursor.seek(&PathSearch::Exact(parent_path), Bias::Right, &()); Self { parent_path, cursor, @@ -1363,7 +1364,7 @@ impl<'a> Iterator for ChildEntriesIter<'a> { if let Some(item) = self.cursor.item() { if item.path().starts_with(self.parent_path) { self.cursor - .seek_forward(&PathSearch::Successor(item.path()), SeekBias::Left, &()); + .seek_forward(&PathSearch::Successor(item.path()), Bias::Left, &()); Some(item) } else { None