From 60ee97be24324184a85037e232f1ffda1a15eca3 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Fri, 25 Jun 2021 17:02:48 -0700 Subject: [PATCH] Always represent anchor as a versioned offset Remove the `Start` and `End` variants, and always use the structure that was previously called `Middle`. This makes Anchors simpler to serialize and deserialize. --- zed/src/editor.rs | 8 +- zed/src/editor/buffer.rs | 145 ++++++++----------------- zed/src/editor/buffer/anchor.rs | 81 ++++++-------- zed/src/editor/display_map/fold_map.rs | 12 +- 4 files changed, 91 insertions(+), 155 deletions(-) diff --git a/zed/src/editor.rs b/zed/src/editor.rs index 6ba540bce3d282f62082f4498584c28e71f01aa8..d356d4f197449578b7ff1eb5fc92aa802adb0f05 100644 --- a/zed/src/editor.rs +++ b/zed/src/editor.rs @@ -1629,7 +1629,7 @@ impl Editor { pub fn select_to_beginning(&mut self, _: &(), cx: &mut ViewContext) { let mut selection = self.selections(cx.as_ref()).last().unwrap().clone(); - selection.set_head(self.buffer.read(cx), Anchor::Start); + selection.set_head(self.buffer.read(cx), Anchor::min()); self.update_selections(vec![selection], true, cx); } @@ -1648,15 +1648,15 @@ impl Editor { pub fn select_to_end(&mut self, _: &(), cx: &mut ViewContext) { let mut selection = self.selections(cx.as_ref()).last().unwrap().clone(); - selection.set_head(self.buffer.read(cx), Anchor::End); + selection.set_head(self.buffer.read(cx), Anchor::max()); self.update_selections(vec![selection], true, cx); } pub fn select_all(&mut self, _: &(), cx: &mut ViewContext) { let selection = Selection { id: post_inc(&mut self.next_selection_id), - start: Anchor::Start, - end: Anchor::End, + start: Anchor::min(), + end: Anchor::max(), reversed: false, goal: SelectionGoal::None, }; diff --git a/zed/src/editor/buffer.rs b/zed/src/editor/buffer.rs index c238bad806ab52fc2d9945f68ffc6f896572a1a7..99b55f98253c665ccd563aedbd130a16dfed3990 100644 --- a/zed/src/editor/buffer.rs +++ b/zed/src/editor/buffer.rs @@ -1493,14 +1493,8 @@ impl Buffer { Operation::UpdateSelections { selections, .. } => { if let Some(selections) = selections { selections.iter().all(|selection| { - let contains_start = match &selection.start { - Anchor::Middle { version, .. } => self.version >= *version, - _ => true, - }; - let contains_end = match &selection.end { - Anchor::Middle { version, .. } => self.version >= *version, - _ => true, - }; + let contains_start = self.version >= selection.start.version; + let contains_end = self.version >= selection.end.version; contains_start && contains_end }) } else { @@ -1645,76 +1639,42 @@ impl Buffer { let offset = position.to_offset(self); let max_offset = self.len(); assert!(offset <= max_offset, "offset is out of range"); - - 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 { - offset: offset + cursor.start().deleted, - bias, - version: self.version(), - } + let mut cursor = self.fragments.cursor::(); + cursor.seek(&offset, bias, &None); + Anchor { + offset: offset + cursor.start().deleted, + bias, + version: self.version(), } } fn summary_for_anchor(&self, anchor: &Anchor) -> TextSummary { - match anchor { - Anchor::Start => TextSummary::default(), - Anchor::End => self.text_summary(), - Anchor::Middle { - offset, - bias, - version, - } => { - 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 - }; - - self.text_summary_for_range(0..cursor.start().1 + overshoot) - } - } + let cx = Some(anchor.version.clone()); + let mut cursor = self + .fragments + .cursor::(); + cursor.seek(&VersionedOffset::Offset(anchor.offset), anchor.bias, &cx); + let overshoot = if cursor.item().map_or(false, |fragment| fragment.visible) { + anchor.offset - cursor.start().0.offset() + } else { + 0 + }; + self.text_summary_for_range(0..cursor.start().1 + overshoot) } 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 - } - } + let cx = Some(anchor.version.clone()); + let mut cursor = self + .fragments + .cursor::(); + cursor.seek(&VersionedOffset::Offset(anchor.offset), anchor.bias, &cx); + let overshoot = if cursor.item().is_some() { + anchor.offset - cursor.start().0.offset() + } else { + 0 + }; + let summary = cursor.start().1; + summary.visible + summary.deleted + overshoot } pub fn point_for_offset(&self, offset: usize) -> Result { @@ -2311,34 +2271,19 @@ impl<'a> Into for &'a EditOperation { impl<'a> Into for &'a Anchor { fn into(self) -> proto::Anchor { - match self { - Anchor::Middle { - offset, - bias, - version, - } => proto::Anchor { - version: version - .iter() - .map(|entry| proto::VectorClockEntry { - replica_id: entry.replica_id as u32, - timestamp: entry.value, - }) - .collect(), - offset: *offset as u64, - bias: match bias { - Bias::Left => proto::anchor::Bias::Left as i32, - Bias::Right => proto::anchor::Bias::Right as i32, - }, - }, - Anchor::Start => proto::Anchor { - version: Vec::new(), - bias: proto::anchor::Bias::Left as i32, - offset: 0, - }, - Anchor::End => proto::Anchor { - version: Vec::new(), - bias: proto::anchor::Bias::Right as i32, - offset: u64::MAX, + proto::Anchor { + version: self + .version + .iter() + .map(|entry| proto::VectorClockEntry { + replica_id: entry.replica_id as u32, + timestamp: entry.value, + }) + .collect(), + offset: self.offset as u64, + bias: match self.bias { + Bias::Left => proto::anchor::Bias::Left as i32, + Bias::Right => proto::anchor::Bias::Right as i32, }, } } @@ -2449,7 +2394,7 @@ impl TryFrom for Anchor { }); } - Ok(Self::Middle { + Ok(Self { offset: message.offset as usize, bias: if message.bias == proto::anchor::Bias::Left as i32 { Bias::Left diff --git a/zed/src/editor/buffer/anchor.rs b/zed/src/editor/buffer/anchor.rs index 6715054ada152df802cb71005233022e15d912c0..474137794d9eecf676441e963b5582bb21f9795a 100644 --- a/zed/src/editor/buffer/anchor.rs +++ b/zed/src/editor/buffer/anchor.rs @@ -4,67 +4,58 @@ use anyhow::Result; use std::{cmp::Ordering, ops::Range}; #[derive(Clone, Eq, PartialEq, Debug, Hash)] -pub enum Anchor { - Start, - End, - Middle { - offset: usize, - bias: Bias, - version: time::Global, - }, +pub struct Anchor { + pub offset: usize, + pub bias: Bias, + pub version: time::Global, } impl Anchor { + pub fn min() -> Self { + Self { + offset: 0, + bias: Bias::Left, + version: Default::default(), + } + } + + pub fn max() -> Self { + Self { + offset: usize::MAX, + bias: Bias::Right, + version: Default::default(), + } + } + pub fn cmp(&self, other: &Anchor, buffer: &Buffer) -> Result { if self == other { return Ok(Ordering::Equal); } - Ok(match (self, other) { - (Anchor::Start, _) | (_, Anchor::End) => Ordering::Less, - (Anchor::End, _) | (_, Anchor::Start) => Ordering::Greater, - ( - Anchor::Middle { - offset: self_offset, - bias: self_bias, - version: self_version, - }, - Anchor::Middle { - offset: other_offset, - bias: other_bias, - version: other_version, - }, - ) => { - 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)) - }; + 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)) - } - }) + Ok(offset_comparison.then_with(|| self.bias.cmp(&other.bias))) } pub fn bias_left(&self, buffer: &Buffer) -> Anchor { - match self { - Anchor::Start - | Anchor::Middle { - bias: Bias::Left, .. - } => self.clone(), - _ => buffer.anchor_before(self), + if self.bias == Bias::Left { + self.clone() + } else { + buffer.anchor_before(self) } } pub fn bias_right(&self, buffer: &Buffer) -> Anchor { - match self { - Anchor::End - | Anchor::Middle { - bias: Bias::Right, .. - } => self.clone(), - _ => buffer.anchor_after(self), + if self.bias == Bias::Right { + self.clone() + } else { + buffer.anchor_after(self) } } } diff --git a/zed/src/editor/display_map/fold_map.rs b/zed/src/editor/display_map/fold_map.rs index 011be31278dcff2886be34ef26482405bc2682fb..8e94bf1eb296d7380f82b168746855d457eff3ee 100644 --- a/zed/src/editor/display_map/fold_map.rs +++ b/zed/src/editor/display_map/fold_map.rs @@ -313,7 +313,7 @@ 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), Bias::Left, buffer); + folds_cursor.seek(&Fold(anchor..Anchor::max()), Bias::Left, buffer); let mut folds = iter::from_fn(move || { let item = folds_cursor .item() @@ -597,7 +597,7 @@ struct Fold(Range); impl Default for Fold { fn default() -> Self { - Self(Anchor::Start..Anchor::End) + Self(Anchor::min()..Anchor::max()) } } @@ -627,10 +627,10 @@ struct FoldSummary { impl Default for FoldSummary { fn default() -> Self { Self { - start: Anchor::Start, - end: Anchor::End, - min_start: Anchor::End, - max_end: Anchor::Start, + start: Anchor::min(), + end: Anchor::max(), + min_start: Anchor::max(), + max_end: Anchor::min(), count: 0, } }