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