anchor.rs

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