anchor.rs

  1use anyhow::Result;
  2use rope::{point::Point, point_utf16::PointUtf16, TextDimension};
  3use std::{cmp::Ordering, fmt::Debug, ops::Range};
  4use sum_tree::Bias;
  5
  6use crate::{BufferSnapshot, ToOffset, ToPoint, ToPointUtf16};
  7
  8#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, Default)]
  9pub struct Anchor {
 10    pub timestamp: clock::Local,
 11    pub offset: usize,
 12    pub bias: Bias,
 13    pub buffer_id: Option<u64>,
 14}
 15
 16impl Anchor {
 17    pub const MIN: Self = Self {
 18        timestamp: clock::Local::MIN,
 19        offset: usize::MIN,
 20        bias: Bias::Left,
 21        buffer_id: None,
 22    };
 23
 24    pub const MAX: Self = Self {
 25        timestamp: clock::Local::MAX,
 26        offset: usize::MAX,
 27        bias: Bias::Right,
 28        buffer_id: None,
 29    };
 30
 31    pub fn cmp(&self, other: &Anchor, buffer: &BufferSnapshot) -> Ordering {
 32        let fragment_id_comparison = if self.timestamp == other.timestamp {
 33            Ordering::Equal
 34        } else {
 35            buffer
 36                .fragment_id_for_anchor(self)
 37                .cmp(buffer.fragment_id_for_anchor(other))
 38        };
 39
 40        fragment_id_comparison
 41            .then_with(|| self.offset.cmp(&other.offset))
 42            .then_with(|| self.bias.cmp(&other.bias))
 43    }
 44
 45    pub fn min(&self, other: &Self, buffer: &BufferSnapshot) -> Self {
 46        if self.cmp(other, buffer).is_le() {
 47            *self
 48        } else {
 49            *other
 50        }
 51    }
 52
 53    pub fn max(&self, other: &Self, buffer: &BufferSnapshot) -> Self {
 54        if self.cmp(other, buffer).is_ge() {
 55            *self
 56        } else {
 57            *other
 58        }
 59    }
 60
 61    pub fn bias(&self, bias: Bias, buffer: &BufferSnapshot) -> Anchor {
 62        if bias == Bias::Left {
 63            self.bias_left(buffer)
 64        } else {
 65            self.bias_right(buffer)
 66        }
 67    }
 68
 69    pub fn bias_left(&self, buffer: &BufferSnapshot) -> Anchor {
 70        if self.bias == Bias::Left {
 71            *self
 72        } else {
 73            buffer.anchor_before(self)
 74        }
 75    }
 76
 77    pub fn bias_right(&self, buffer: &BufferSnapshot) -> Anchor {
 78        if self.bias == Bias::Right {
 79            *self
 80        } else {
 81            buffer.anchor_after(self)
 82        }
 83    }
 84
 85    pub fn summary<D>(&self, content: &BufferSnapshot) -> D
 86    where
 87        D: TextDimension,
 88    {
 89        content.summary_for_anchor(self)
 90    }
 91}
 92
 93pub trait OffsetRangeExt {
 94    fn to_offset(&self, snapshot: &BufferSnapshot) -> Range<usize>;
 95    fn to_point(&self, snapshot: &BufferSnapshot) -> Range<Point>;
 96    fn to_point_utf16(&self, snapshot: &BufferSnapshot) -> Range<PointUtf16>;
 97}
 98
 99impl<T> OffsetRangeExt for Range<T>
100where
101    T: ToOffset,
102{
103    fn to_offset(&self, snapshot: &BufferSnapshot) -> Range<usize> {
104        self.start.to_offset(snapshot)..self.end.to_offset(snapshot)
105    }
106
107    fn to_point(&self, snapshot: &BufferSnapshot) -> Range<Point> {
108        self.start.to_offset(snapshot).to_point(snapshot)
109            ..self.end.to_offset(snapshot).to_point(snapshot)
110    }
111
112    fn to_point_utf16(&self, snapshot: &BufferSnapshot) -> Range<PointUtf16> {
113        self.start.to_offset(snapshot).to_point_utf16(snapshot)
114            ..self.end.to_offset(snapshot).to_point_utf16(snapshot)
115    }
116}
117
118pub trait AnchorRangeExt {
119    fn cmp(&self, b: &Range<Anchor>, buffer: &BufferSnapshot) -> Result<Ordering>;
120}
121
122impl AnchorRangeExt for Range<Anchor> {
123    fn cmp(&self, other: &Range<Anchor>, buffer: &BufferSnapshot) -> Result<Ordering> {
124        Ok(match self.start.cmp(&other.start, buffer) {
125            Ordering::Equal => other.end.cmp(&self.end, buffer),
126            ord => ord,
127        })
128    }
129}