anchor.rs

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