anchor.rs

  1use super::{ExcerptId, MultiBufferSnapshot, ToOffset, ToPoint};
  2use anyhow::Result;
  3use std::{
  4    cmp::Ordering,
  5    ops::{Range, Sub},
  6};
  7use sum_tree::Bias;
  8use text::{rope::TextDimension, Point};
  9
 10#[derive(Clone, Eq, PartialEq, Debug, Hash)]
 11pub struct Anchor {
 12    pub(crate) buffer_id: Option<usize>,
 13    pub(crate) excerpt_id: ExcerptId,
 14    pub(crate) text_anchor: text::Anchor,
 15}
 16
 17impl Anchor {
 18    pub fn min() -> Self {
 19        Self {
 20            buffer_id: None,
 21            excerpt_id: ExcerptId::min(),
 22            text_anchor: text::Anchor::min(),
 23        }
 24    }
 25
 26    pub fn max() -> Self {
 27        Self {
 28            buffer_id: None,
 29            excerpt_id: ExcerptId::max(),
 30            text_anchor: text::Anchor::max(),
 31        }
 32    }
 33
 34    pub fn excerpt_id(&self) -> &ExcerptId {
 35        &self.excerpt_id
 36    }
 37
 38    pub fn cmp<'a>(&self, other: &Anchor, snapshot: &MultiBufferSnapshot) -> Result<Ordering> {
 39        let excerpt_id_cmp = self.excerpt_id.cmp(&other.excerpt_id);
 40        if excerpt_id_cmp.is_eq() {
 41            if self.excerpt_id == ExcerptId::min() || self.excerpt_id == ExcerptId::max() {
 42                Ok(Ordering::Equal)
 43            } else if let Some(excerpt) = snapshot.excerpt(&self.excerpt_id) {
 44                // Even though the anchor refers to a valid excerpt the underlying buffer might have
 45                // changed. In that case, treat the anchor as if it were at the start of that
 46                // excerpt.
 47                if self.buffer_id == Some(excerpt.buffer_id)
 48                    && other.buffer_id == Some(excerpt.buffer_id)
 49                {
 50                    let self_anchor = excerpt.clip_anchor(self.text_anchor.clone());
 51                    let other_anchor = excerpt.clip_anchor(other.text_anchor.clone());
 52                    self_anchor.cmp(&other_anchor, &excerpt.buffer)
 53                } else if self.buffer_id == Some(excerpt.buffer_id) {
 54                    Ok(Ordering::Greater)
 55                } else if other.buffer_id == Some(excerpt.buffer_id) {
 56                    Ok(Ordering::Less)
 57                } else {
 58                    Ok(Ordering::Equal)
 59                }
 60            } else {
 61                Ok(Ordering::Equal)
 62            }
 63        } else {
 64            Ok(excerpt_id_cmp)
 65        }
 66    }
 67
 68    pub fn bias_left(&self, snapshot: &MultiBufferSnapshot) -> Anchor {
 69        if self.text_anchor.bias != Bias::Left {
 70            if let Some(excerpt) = snapshot.excerpt(&self.excerpt_id) {
 71                if self.buffer_id == Some(excerpt.buffer_id) {
 72                    return Self {
 73                        buffer_id: self.buffer_id,
 74                        excerpt_id: self.excerpt_id.clone(),
 75                        text_anchor: self.text_anchor.bias_left(&excerpt.buffer),
 76                    };
 77                }
 78            }
 79        }
 80        self.clone()
 81    }
 82
 83    pub fn bias_right(&self, snapshot: &MultiBufferSnapshot) -> Anchor {
 84        if self.text_anchor.bias != Bias::Right {
 85            if let Some(excerpt) = snapshot.excerpt(&self.excerpt_id) {
 86                if self.buffer_id == Some(excerpt.buffer_id) {
 87                    return Self {
 88                        buffer_id: self.buffer_id,
 89                        excerpt_id: self.excerpt_id.clone(),
 90                        text_anchor: self.text_anchor.bias_right(&excerpt.buffer),
 91                    };
 92                }
 93            }
 94        }
 95        self.clone()
 96    }
 97
 98    pub fn summary<D>(&self, snapshot: &MultiBufferSnapshot) -> D
 99    where
100        D: TextDimension + Ord + Sub<D, Output = D>,
101    {
102        snapshot.summary_for_anchor(self)
103    }
104}
105
106impl ToOffset for Anchor {
107    fn to_offset(&self, snapshot: &MultiBufferSnapshot) -> usize {
108        self.summary(snapshot)
109    }
110}
111
112impl ToPoint for Anchor {
113    fn to_point<'a>(&self, snapshot: &MultiBufferSnapshot) -> Point {
114        self.summary(snapshot)
115    }
116}
117
118pub trait AnchorRangeExt {
119    fn cmp(&self, b: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> Result<Ordering>;
120    fn to_offset(&self, content: &MultiBufferSnapshot) -> Range<usize>;
121    fn to_point(&self, content: &MultiBufferSnapshot) -> Range<Point>;
122}
123
124impl AnchorRangeExt for Range<Anchor> {
125    fn cmp(&self, other: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> Result<Ordering> {
126        Ok(match self.start.cmp(&other.start, buffer)? {
127            Ordering::Equal => other.end.cmp(&self.end, buffer)?,
128            ord @ _ => ord,
129        })
130    }
131
132    fn to_offset(&self, content: &MultiBufferSnapshot) -> Range<usize> {
133        self.start.to_offset(&content)..self.end.to_offset(&content)
134    }
135
136    fn to_point(&self, content: &MultiBufferSnapshot) -> Range<Point> {
137        self.start.to_point(&content)..self.end.to_point(&content)
138    }
139}