anchor.rs

  1use super::{ExcerptId, MultiBufferSnapshot, ToOffset, ToOffsetUtf16, ToPoint};
  2use language::{OffsetUtf16, Point, TextDimension};
  3use std::{
  4    cmp::Ordering,
  5    ops::{Range, Sub},
  6};
  7use sum_tree::Bias;
  8use text::BufferId;
  9
 10#[derive(Clone, Copy, Eq, PartialEq, Debug, Hash)]
 11pub struct Anchor {
 12    pub buffer_id: Option<BufferId>,
 13    pub excerpt_id: ExcerptId,
 14    pub text_anchor: text::Anchor,
 15    pub diff_base_anchor: Option<text::Anchor>,
 16}
 17
 18impl Anchor {
 19    pub fn in_buffer(
 20        excerpt_id: ExcerptId,
 21        buffer_id: BufferId,
 22        text_anchor: text::Anchor,
 23    ) -> Self {
 24        Self {
 25            buffer_id: Some(buffer_id),
 26            excerpt_id,
 27            text_anchor,
 28            diff_base_anchor: None,
 29        }
 30    }
 31
 32    pub fn range_in_buffer(
 33        excerpt_id: ExcerptId,
 34        buffer_id: BufferId,
 35        range: Range<text::Anchor>,
 36    ) -> Range<Self> {
 37        Self::in_buffer(excerpt_id, buffer_id, range.start)
 38            ..Self::in_buffer(excerpt_id, buffer_id, range.end)
 39    }
 40
 41    pub fn min() -> Self {
 42        Self {
 43            buffer_id: None,
 44            excerpt_id: ExcerptId::min(),
 45            text_anchor: text::Anchor::MIN,
 46            diff_base_anchor: None,
 47        }
 48    }
 49
 50    pub fn max() -> Self {
 51        Self {
 52            buffer_id: None,
 53            excerpt_id: ExcerptId::max(),
 54            text_anchor: text::Anchor::MAX,
 55            diff_base_anchor: None,
 56        }
 57    }
 58
 59    pub fn cmp(&self, other: &Anchor, snapshot: &MultiBufferSnapshot) -> Ordering {
 60        let excerpt_id_cmp = self.excerpt_id.cmp(&other.excerpt_id, snapshot);
 61        if excerpt_id_cmp.is_ne() {
 62            return excerpt_id_cmp;
 63        }
 64        if self.excerpt_id == ExcerptId::min() || self.excerpt_id == ExcerptId::max() {
 65            return Ordering::Equal;
 66        }
 67        if let Some(excerpt) = snapshot.excerpt(self.excerpt_id) {
 68            let text_cmp = self.text_anchor.cmp(&other.text_anchor, &excerpt.buffer);
 69            if text_cmp.is_ne() {
 70                return text_cmp;
 71            }
 72            if self.diff_base_anchor.is_some() || other.diff_base_anchor.is_some() {
 73                if let Some(diff_base) = snapshot.diffs.get(&excerpt.buffer_id) {
 74                    let self_anchor = self
 75                        .diff_base_anchor
 76                        .filter(|a| diff_base.base_text.can_resolve(a));
 77                    let other_anchor = other
 78                        .diff_base_anchor
 79                        .filter(|a| diff_base.base_text.can_resolve(a));
 80                    return match (self_anchor, other_anchor) {
 81                        (Some(a), Some(b)) => a.cmp(&b, &diff_base.base_text),
 82                        (Some(_), None) => match other.text_anchor.bias {
 83                            Bias::Left => Ordering::Greater,
 84                            Bias::Right => Ordering::Less,
 85                        },
 86                        (None, Some(_)) => match self.text_anchor.bias {
 87                            Bias::Left => Ordering::Less,
 88                            Bias::Right => Ordering::Greater,
 89                        },
 90                        (None, None) => Ordering::Equal,
 91                    };
 92                }
 93            }
 94        }
 95        Ordering::Equal
 96    }
 97
 98    pub fn bias(&self) -> Bias {
 99        self.text_anchor.bias
100    }
101
102    pub fn bias_left(&self, snapshot: &MultiBufferSnapshot) -> Anchor {
103        if self.text_anchor.bias != Bias::Left {
104            if let Some(excerpt) = snapshot.excerpt(self.excerpt_id) {
105                return Self {
106                    buffer_id: self.buffer_id,
107                    excerpt_id: self.excerpt_id,
108                    text_anchor: self.text_anchor.bias_left(&excerpt.buffer),
109                    diff_base_anchor: self.diff_base_anchor.map(|a| {
110                        if let Some(base) = snapshot.diffs.get(&excerpt.buffer_id) {
111                            if a.buffer_id == Some(base.base_text.remote_id()) {
112                                return a.bias_left(&base.base_text);
113                            }
114                        }
115                        a
116                    }),
117                };
118            }
119        }
120        *self
121    }
122
123    pub fn bias_right(&self, snapshot: &MultiBufferSnapshot) -> Anchor {
124        if self.text_anchor.bias != Bias::Right {
125            if let Some(excerpt) = snapshot.excerpt(self.excerpt_id) {
126                return Self {
127                    buffer_id: self.buffer_id,
128                    excerpt_id: self.excerpt_id,
129                    text_anchor: self.text_anchor.bias_right(&excerpt.buffer),
130                    diff_base_anchor: self.diff_base_anchor.map(|a| {
131                        if let Some(base) = snapshot.diffs.get(&excerpt.buffer_id) {
132                            if a.buffer_id == Some(base.base_text.remote_id()) {
133                                return a.bias_right(&base.base_text);
134                            }
135                        }
136                        a
137                    }),
138                };
139            }
140        }
141        *self
142    }
143
144    pub fn summary<D>(&self, snapshot: &MultiBufferSnapshot) -> D
145    where
146        D: TextDimension + Ord + Sub<D, Output = D>,
147    {
148        snapshot.summary_for_anchor(self)
149    }
150
151    pub fn is_valid(&self, snapshot: &MultiBufferSnapshot) -> bool {
152        if *self == Anchor::min() || *self == Anchor::max() {
153            true
154        } else if let Some(excerpt) = snapshot.excerpt(self.excerpt_id) {
155            excerpt.contains(self)
156                && (self.text_anchor == excerpt.range.context.start
157                    || self.text_anchor == excerpt.range.context.end
158                    || self.text_anchor.is_valid(&excerpt.buffer))
159        } else {
160            false
161        }
162    }
163}
164
165impl ToOffset for Anchor {
166    fn to_offset(&self, snapshot: &MultiBufferSnapshot) -> usize {
167        self.summary(snapshot)
168    }
169}
170
171impl ToOffsetUtf16 for Anchor {
172    fn to_offset_utf16(&self, snapshot: &MultiBufferSnapshot) -> OffsetUtf16 {
173        self.summary(snapshot)
174    }
175}
176
177impl ToPoint for Anchor {
178    fn to_point<'a>(&self, snapshot: &MultiBufferSnapshot) -> Point {
179        self.summary(snapshot)
180    }
181}
182
183pub trait AnchorRangeExt {
184    fn cmp(&self, b: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> Ordering;
185    fn overlaps(&self, b: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> bool;
186    fn to_offset(&self, content: &MultiBufferSnapshot) -> Range<usize>;
187    fn to_point(&self, content: &MultiBufferSnapshot) -> Range<Point>;
188}
189
190impl AnchorRangeExt for Range<Anchor> {
191    fn cmp(&self, other: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> Ordering {
192        match self.start.cmp(&other.start, buffer) {
193            Ordering::Equal => other.end.cmp(&self.end, buffer),
194            ord => ord,
195        }
196    }
197
198    fn overlaps(&self, other: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> bool {
199        self.end.cmp(&other.start, buffer).is_ge() && self.start.cmp(&other.end, buffer).is_le()
200    }
201
202    fn to_offset(&self, content: &MultiBufferSnapshot) -> Range<usize> {
203        self.start.to_offset(content)..self.end.to_offset(content)
204    }
205
206    fn to_point(&self, content: &MultiBufferSnapshot) -> Range<Point> {
207        self.start.to_point(content)..self.end.to_point(content)
208    }
209}
210
211#[derive(Clone, Copy, Eq, PartialEq, Debug, Hash, Ord, PartialOrd)]
212pub struct Offset(pub usize);