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        if self == other {
 61            return Ordering::Equal;
 62        }
 63
 64        let self_excerpt_id = snapshot.latest_excerpt_id(self.excerpt_id);
 65        let other_excerpt_id = snapshot.latest_excerpt_id(other.excerpt_id);
 66
 67        let excerpt_id_cmp = self_excerpt_id.cmp(&other_excerpt_id, snapshot);
 68        if excerpt_id_cmp.is_ne() {
 69            return excerpt_id_cmp;
 70        }
 71        if self_excerpt_id == ExcerptId::min() || self_excerpt_id == ExcerptId::max() {
 72            return Ordering::Equal;
 73        }
 74        if let Some(excerpt) = snapshot.excerpt(self_excerpt_id) {
 75            let text_cmp = self.text_anchor.cmp(&other.text_anchor, &excerpt.buffer);
 76            if text_cmp.is_ne() {
 77                return text_cmp;
 78            }
 79            if self.diff_base_anchor.is_some() || other.diff_base_anchor.is_some() {
 80                if let Some(base_text) = snapshot
 81                    .diffs
 82                    .get(&excerpt.buffer_id)
 83                    .map(|diff| diff.base_text())
 84                {
 85                    let self_anchor = self.diff_base_anchor.filter(|a| base_text.can_resolve(a));
 86                    let other_anchor = other.diff_base_anchor.filter(|a| base_text.can_resolve(a));
 87                    return match (self_anchor, other_anchor) {
 88                        (Some(a), Some(b)) => a.cmp(&b, base_text),
 89                        (Some(_), None) => match other.text_anchor.bias {
 90                            Bias::Left => Ordering::Greater,
 91                            Bias::Right => Ordering::Less,
 92                        },
 93                        (None, Some(_)) => match self.text_anchor.bias {
 94                            Bias::Left => Ordering::Less,
 95                            Bias::Right => Ordering::Greater,
 96                        },
 97                        (None, None) => Ordering::Equal,
 98                    };
 99                }
100            }
101        }
102        Ordering::Equal
103    }
104
105    pub fn bias(&self) -> Bias {
106        self.text_anchor.bias
107    }
108
109    pub fn bias_left(&self, snapshot: &MultiBufferSnapshot) -> Anchor {
110        if self.text_anchor.bias != Bias::Left {
111            if let Some(excerpt) = snapshot.excerpt(self.excerpt_id) {
112                return Self {
113                    buffer_id: self.buffer_id,
114                    excerpt_id: self.excerpt_id,
115                    text_anchor: self.text_anchor.bias_left(&excerpt.buffer),
116                    diff_base_anchor: self.diff_base_anchor.map(|a| {
117                        if let Some(base_text) = snapshot
118                            .diffs
119                            .get(&excerpt.buffer_id)
120                            .map(|diff| diff.base_text())
121                        {
122                            if a.buffer_id == Some(base_text.remote_id()) {
123                                return a.bias_left(base_text);
124                            }
125                        }
126                        a
127                    }),
128                };
129            }
130        }
131        *self
132    }
133
134    pub fn bias_right(&self, snapshot: &MultiBufferSnapshot) -> Anchor {
135        if self.text_anchor.bias != Bias::Right {
136            if let Some(excerpt) = snapshot.excerpt(self.excerpt_id) {
137                return Self {
138                    buffer_id: self.buffer_id,
139                    excerpt_id: self.excerpt_id,
140                    text_anchor: self.text_anchor.bias_right(&excerpt.buffer),
141                    diff_base_anchor: self.diff_base_anchor.map(|a| {
142                        if let Some(base_text) = snapshot
143                            .diffs
144                            .get(&excerpt.buffer_id)
145                            .map(|diff| diff.base_text())
146                        {
147                            if a.buffer_id == Some(base_text.remote_id()) {
148                                return a.bias_right(&base_text);
149                            }
150                        }
151                        a
152                    }),
153                };
154            }
155        }
156        *self
157    }
158
159    pub fn summary<D>(&self, snapshot: &MultiBufferSnapshot) -> D
160    where
161        D: TextDimension + Ord + Sub<D, Output = D>,
162    {
163        snapshot.summary_for_anchor(self)
164    }
165
166    pub fn is_valid(&self, snapshot: &MultiBufferSnapshot) -> bool {
167        if *self == Anchor::min() || *self == Anchor::max() {
168            true
169        } else if let Some(excerpt) = snapshot.excerpt(self.excerpt_id) {
170            (self.text_anchor == excerpt.range.context.start
171                || self.text_anchor == excerpt.range.context.end
172                || self.text_anchor.is_valid(&excerpt.buffer))
173                && excerpt.contains(self)
174        } else {
175            false
176        }
177    }
178}
179
180impl ToOffset for Anchor {
181    fn to_offset(&self, snapshot: &MultiBufferSnapshot) -> usize {
182        self.summary(snapshot)
183    }
184}
185
186impl ToOffsetUtf16 for Anchor {
187    fn to_offset_utf16(&self, snapshot: &MultiBufferSnapshot) -> OffsetUtf16 {
188        self.summary(snapshot)
189    }
190}
191
192impl ToPoint for Anchor {
193    fn to_point<'a>(&self, snapshot: &MultiBufferSnapshot) -> Point {
194        self.summary(snapshot)
195    }
196}
197
198pub trait AnchorRangeExt {
199    fn cmp(&self, other: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> Ordering;
200    fn includes(&self, other: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> bool;
201    fn overlaps(&self, other: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> bool;
202    fn to_offset(&self, content: &MultiBufferSnapshot) -> Range<usize>;
203    fn to_point(&self, content: &MultiBufferSnapshot) -> Range<Point>;
204}
205
206impl AnchorRangeExt for Range<Anchor> {
207    fn cmp(&self, other: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> Ordering {
208        match self.start.cmp(&other.start, buffer) {
209            Ordering::Equal => other.end.cmp(&self.end, buffer),
210            ord => ord,
211        }
212    }
213
214    fn includes(&self, other: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> bool {
215        self.start.cmp(&other.start, &buffer).is_le() && other.end.cmp(&self.end, &buffer).is_le()
216    }
217
218    fn overlaps(&self, other: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> bool {
219        self.end.cmp(&other.start, buffer).is_ge() && self.start.cmp(&other.end, buffer).is_le()
220    }
221
222    fn to_offset(&self, content: &MultiBufferSnapshot) -> Range<usize> {
223        self.start.to_offset(content)..self.end.to_offset(content)
224    }
225
226    fn to_point(&self, content: &MultiBufferSnapshot) -> Range<Point> {
227        self.start.to_point(content)..self.end.to_point(content)
228    }
229}
230
231#[derive(Clone, Copy, Eq, PartialEq, Debug, Hash, Ord, PartialOrd)]
232pub struct Offset(pub usize);