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