anchor.rs

  1use super::{ExcerptId, MultiBufferSnapshot, ToOffset, ToPoint};
  2use anyhow::{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) excerpt_id: ExcerptId,
 13    pub(crate) text_anchor: text::Anchor,
 14}
 15
 16impl Anchor {
 17    pub fn min() -> Self {
 18        Self {
 19            excerpt_id: ExcerptId::min(),
 20            text_anchor: text::Anchor::min(),
 21        }
 22    }
 23
 24    pub fn max() -> Self {
 25        Self {
 26            excerpt_id: ExcerptId::max(),
 27            text_anchor: text::Anchor::max(),
 28        }
 29    }
 30
 31    pub fn excerpt_id(&self) -> &ExcerptId {
 32        &self.excerpt_id
 33    }
 34
 35    pub fn cmp<'a>(&self, other: &Anchor, snapshot: &MultiBufferSnapshot) -> Result<Ordering> {
 36        let excerpt_id_cmp = self.excerpt_id.cmp(&other.excerpt_id);
 37        if excerpt_id_cmp.is_eq() {
 38            if self.excerpt_id == ExcerptId::min() || self.excerpt_id == ExcerptId::max() {
 39                Ok(Ordering::Equal)
 40            } else {
 41                self.text_anchor.cmp(
 42                    &other.text_anchor,
 43                    snapshot
 44                        .buffer_snapshot_for_excerpt(&self.excerpt_id)
 45                        .ok_or_else(|| anyhow!("excerpt {:?} not found", self.excerpt_id))?,
 46                )
 47            }
 48        } else {
 49            return Ok(excerpt_id_cmp);
 50        }
 51    }
 52
 53    pub fn bias_left(&self, snapshot: &MultiBufferSnapshot) -> Anchor {
 54        if self.text_anchor.bias != Bias::Left {
 55            if let Some(buffer_snapshot) = snapshot.buffer_snapshot_for_excerpt(&self.excerpt_id) {
 56                return Self {
 57                    excerpt_id: self.excerpt_id.clone(),
 58                    text_anchor: self.text_anchor.bias_left(buffer_snapshot),
 59                };
 60            }
 61        }
 62        self.clone()
 63    }
 64
 65    pub fn bias_right(&self, snapshot: &MultiBufferSnapshot) -> Anchor {
 66        if self.text_anchor.bias != Bias::Right {
 67            if let Some(buffer_snapshot) = snapshot.buffer_snapshot_for_excerpt(&self.excerpt_id) {
 68                return Self {
 69                    excerpt_id: self.excerpt_id.clone(),
 70                    text_anchor: self.text_anchor.bias_right(buffer_snapshot),
 71                };
 72            }
 73        }
 74        self.clone()
 75    }
 76
 77    pub fn summary<D>(&self, snapshot: &MultiBufferSnapshot) -> D
 78    where
 79        D: TextDimension + Ord + Sub<D, Output = D>,
 80    {
 81        snapshot.summary_for_anchor(self)
 82    }
 83}
 84
 85impl ToOffset for Anchor {
 86    fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
 87        self.summary(snapshot)
 88    }
 89}
 90
 91impl ToPoint for Anchor {
 92    fn to_point<'a>(&self, snapshot: &MultiBufferSnapshot) -> Point {
 93        self.summary(snapshot)
 94    }
 95}
 96
 97pub trait AnchorRangeExt {
 98    fn cmp(&self, b: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> Result<Ordering>;
 99    fn to_offset(&self, content: &MultiBufferSnapshot) -> Range<usize>;
100    fn to_point(&self, content: &MultiBufferSnapshot) -> Range<Point>;
101}
102
103impl AnchorRangeExt for Range<Anchor> {
104    fn cmp(&self, other: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> Result<Ordering> {
105        Ok(match self.start.cmp(&other.start, buffer)? {
106            Ordering::Equal => other.end.cmp(&self.end, buffer)?,
107            ord @ _ => ord,
108        })
109    }
110
111    fn to_offset(&self, content: &MultiBufferSnapshot) -> Range<usize> {
112        self.start.to_offset(&content)..self.end.to_offset(&content)
113    }
114
115    fn to_point(&self, content: &MultiBufferSnapshot) -> Range<Point> {
116        self.start.to_point(&content)..self.end.to_point(&content)
117    }
118}