anchor.rs

  1use crate::{rope::TextDimension, Snapshot};
  2
  3use super::{Buffer, ToOffset};
  4use anyhow::Result;
  5use std::{cmp::Ordering, fmt::Debug, ops::Range};
  6use sum_tree::Bias;
  7
  8#[derive(Clone, Eq, PartialEq, Debug, Hash)]
  9pub enum Anchor {
 10    Min,
 11    Insertion {
 12        timestamp: clock::Local,
 13        offset: usize,
 14        bias: Bias,
 15    },
 16    Max,
 17}
 18
 19impl Anchor {
 20    pub fn min() -> Self {
 21        Self::Min
 22    }
 23
 24    pub fn max() -> Self {
 25        Self::Max
 26    }
 27
 28    pub fn cmp<'a>(&self, other: &Anchor, buffer: &Snapshot) -> Result<Ordering> {
 29        match (self, other) {
 30            (Self::Min, Self::Min) => Ok(Ordering::Equal),
 31            (Self::Min, _) => Ok(Ordering::Less),
 32            (_, Self::Min) => Ok(Ordering::Greater),
 33            (Self::Max, Self::Max) => Ok(Ordering::Equal),
 34            (Self::Max, _) => Ok(Ordering::Greater),
 35            (_, Self::Max) => Ok(Ordering::Less),
 36            (
 37                Self::Insertion {
 38                    timestamp: lhs_id,
 39                    bias: lhs_bias,
 40                    offset: lhs_offset,
 41                },
 42                Self::Insertion {
 43                    timestamp: rhs_id,
 44                    bias: rhs_bias,
 45                    offset: rhs_offset,
 46                },
 47            ) => {
 48                let offset_comparison = if lhs_id == rhs_id {
 49                    lhs_offset.cmp(&rhs_offset)
 50                } else {
 51                    buffer
 52                        .full_offset_for_anchor(self)
 53                        .cmp(&buffer.full_offset_for_anchor(other))
 54                };
 55
 56                Ok(offset_comparison.then_with(|| lhs_bias.cmp(&rhs_bias)))
 57            }
 58        }
 59    }
 60
 61    pub fn bias_left(&self, buffer: &Buffer) -> Anchor {
 62        match self {
 63            Anchor::Min => Anchor::Min,
 64            Anchor::Insertion { bias, .. } => {
 65                if *bias == Bias::Left {
 66                    self.clone()
 67                } else {
 68                    buffer.anchor_before(self)
 69                }
 70            }
 71            Anchor::Max => buffer.anchor_before(self),
 72        }
 73    }
 74
 75    pub fn bias_right(&self, buffer: &Buffer) -> Anchor {
 76        match self {
 77            Anchor::Min => buffer.anchor_after(self),
 78            Anchor::Insertion { bias, .. } => {
 79                if *bias == Bias::Right {
 80                    self.clone()
 81                } else {
 82                    buffer.anchor_after(self)
 83                }
 84            }
 85            Anchor::Max => Anchor::Max,
 86        }
 87    }
 88
 89    pub fn summary<'a, D>(&self, content: &'a Snapshot) -> D
 90    where
 91        D: TextDimension<'a>,
 92    {
 93        content.summary_for_anchor(self)
 94    }
 95}
 96
 97pub trait AnchorRangeExt {
 98    fn cmp(&self, b: &Range<Anchor>, buffer: &Snapshot) -> Result<Ordering>;
 99    fn to_offset(&self, content: &Snapshot) -> Range<usize>;
100}
101
102impl AnchorRangeExt for Range<Anchor> {
103    fn cmp(&self, other: &Range<Anchor>, buffer: &Snapshot) -> Result<Ordering> {
104        Ok(match self.start.cmp(&other.start, buffer)? {
105            Ordering::Equal => other.end.cmp(&self.end, buffer)?,
106            ord @ _ => ord,
107        })
108    }
109
110    fn to_offset(&self, content: &Snapshot) -> Range<usize> {
111        self.start.to_offset(&content)..self.end.to_offset(&content)
112    }
113}