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}
16
17impl Anchor {
18 pub fn min() -> Self {
19 Self {
20 buffer_id: None,
21 excerpt_id: ExcerptId::min(),
22 text_anchor: text::Anchor::MIN,
23 }
24 }
25
26 pub fn max() -> Self {
27 Self {
28 buffer_id: None,
29 excerpt_id: ExcerptId::max(),
30 text_anchor: text::Anchor::MAX,
31 }
32 }
33
34 pub fn cmp(&self, other: &Anchor, snapshot: &MultiBufferSnapshot) -> Ordering {
35 let excerpt_id_cmp = self.excerpt_id.cmp(&other.excerpt_id, snapshot);
36 if excerpt_id_cmp.is_eq() {
37 if self.excerpt_id == ExcerptId::min() || self.excerpt_id == ExcerptId::max() {
38 Ordering::Equal
39 } else if let Some(excerpt) = snapshot.excerpt(self.excerpt_id) {
40 self.text_anchor.cmp(&other.text_anchor, &excerpt.buffer)
41 } else {
42 Ordering::Equal
43 }
44 } else {
45 excerpt_id_cmp
46 }
47 }
48
49 pub fn bias(&self) -> Bias {
50 self.text_anchor.bias
51 }
52
53 pub fn bias_left(&self, snapshot: &MultiBufferSnapshot) -> Anchor {
54 if self.text_anchor.bias != Bias::Left {
55 if let Some(excerpt) = snapshot.excerpt(self.excerpt_id) {
56 return Self {
57 buffer_id: self.buffer_id,
58 excerpt_id: self.excerpt_id,
59 text_anchor: self.text_anchor.bias_left(&excerpt.buffer),
60 };
61 }
62 }
63 *self
64 }
65
66 pub fn bias_right(&self, snapshot: &MultiBufferSnapshot) -> Anchor {
67 if self.text_anchor.bias != Bias::Right {
68 if let Some(excerpt) = snapshot.excerpt(self.excerpt_id) {
69 return Self {
70 buffer_id: self.buffer_id,
71 excerpt_id: self.excerpt_id,
72 text_anchor: self.text_anchor.bias_right(&excerpt.buffer),
73 };
74 }
75 }
76 *self
77 }
78
79 pub fn summary<D>(&self, snapshot: &MultiBufferSnapshot) -> D
80 where
81 D: TextDimension + Ord + Sub<D, Output = D>,
82 {
83 snapshot.summary_for_anchor(self)
84 }
85
86 pub fn is_valid(&self, snapshot: &MultiBufferSnapshot) -> bool {
87 if *self == Anchor::min() || *self == Anchor::max() {
88 true
89 } else if let Some(excerpt) = snapshot.excerpt(self.excerpt_id) {
90 excerpt.contains(self)
91 && (self.text_anchor == excerpt.range.context.start
92 || self.text_anchor == excerpt.range.context.end
93 || self.text_anchor.is_valid(&excerpt.buffer))
94 } else {
95 false
96 }
97 }
98}
99
100impl ToOffset for Anchor {
101 fn to_offset(&self, snapshot: &MultiBufferSnapshot) -> usize {
102 self.summary(snapshot)
103 }
104}
105
106impl ToOffsetUtf16 for Anchor {
107 fn to_offset_utf16(&self, snapshot: &MultiBufferSnapshot) -> OffsetUtf16 {
108 self.summary(snapshot)
109 }
110}
111
112impl ToPoint for Anchor {
113 fn to_point<'a>(&self, snapshot: &MultiBufferSnapshot) -> Point {
114 self.summary(snapshot)
115 }
116}
117
118pub trait AnchorRangeExt {
119 fn cmp(&self, b: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> Ordering;
120 fn overlaps(&self, b: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> bool;
121 fn to_offset(&self, content: &MultiBufferSnapshot) -> Range<usize>;
122 fn to_point(&self, content: &MultiBufferSnapshot) -> Range<Point>;
123}
124
125impl AnchorRangeExt for Range<Anchor> {
126 fn cmp(&self, other: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> Ordering {
127 match self.start.cmp(&other.start, buffer) {
128 Ordering::Equal => other.end.cmp(&self.end, buffer),
129 ord => ord,
130 }
131 }
132
133 fn overlaps(&self, other: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> bool {
134 self.end.cmp(&other.start, buffer).is_ge() && self.start.cmp(&other.end, buffer).is_le()
135 }
136
137 fn to_offset(&self, content: &MultiBufferSnapshot) -> Range<usize> {
138 self.start.to_offset(content)..self.end.to_offset(content)
139 }
140
141 fn to_point(&self, content: &MultiBufferSnapshot) -> Range<Point> {
142 self.start.to_point(content)..self.end.to_point(content)
143 }
144}
145
146#[derive(Clone, Copy, Eq, PartialEq, Debug, Hash, Ord, PartialOrd)]
147pub struct Offset(pub usize);