anchor.rs

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