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