1use super::{ExcerptId, MultiBufferSnapshot, ToOffset, ToPoint};
2use anyhow::Result;
3use std::{
4 cmp::Ordering,
5 ops::{Range, Sub},
6};
7use sum_tree::Bias;
8use text::{rope::TextDimension, Point};
9
10#[derive(Clone, Eq, PartialEq, Debug, Hash)]
11pub struct Anchor {
12 pub(crate) buffer_id: Option<usize>,
13 pub(crate) excerpt_id: ExcerptId,
14 pub(crate) 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 excerpt_id(&self) -> &ExcerptId {
35 &self.excerpt_id
36 }
37
38 pub fn cmp<'a>(&self, other: &Anchor, snapshot: &MultiBufferSnapshot) -> Result<Ordering> {
39 let excerpt_id_cmp = self.excerpt_id.cmp(&other.excerpt_id);
40 if excerpt_id_cmp.is_eq() {
41 if self.excerpt_id == ExcerptId::min() || self.excerpt_id == ExcerptId::max() {
42 Ok(Ordering::Equal)
43 } else if let Some(excerpt) = snapshot.excerpt(&self.excerpt_id) {
44 self.text_anchor.cmp(&other.text_anchor, &excerpt.buffer)
45 } else {
46 Ok(Ordering::Equal)
47 }
48 } else {
49 Ok(excerpt_id_cmp)
50 }
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.clone(),
59 text_anchor: self.text_anchor.bias_left(&excerpt.buffer),
60 };
61 }
62 }
63 self.clone()
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.clone(),
72 text_anchor: self.text_anchor.bias_right(&excerpt.buffer),
73 };
74 }
75 }
76 self.clone()
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
87impl ToOffset for Anchor {
88 fn to_offset(&self, snapshot: &MultiBufferSnapshot) -> usize {
89 self.summary(snapshot)
90 }
91}
92
93impl ToPoint for Anchor {
94 fn to_point<'a>(&self, snapshot: &MultiBufferSnapshot) -> Point {
95 self.summary(snapshot)
96 }
97}
98
99pub trait AnchorRangeExt {
100 fn cmp(&self, b: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> Result<Ordering>;
101 fn to_offset(&self, content: &MultiBufferSnapshot) -> Range<usize>;
102 fn to_point(&self, content: &MultiBufferSnapshot) -> Range<Point>;
103}
104
105impl AnchorRangeExt for Range<Anchor> {
106 fn cmp(&self, other: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> Result<Ordering> {
107 Ok(match self.start.cmp(&other.start, buffer)? {
108 Ordering::Equal => other.end.cmp(&self.end, buffer)?,
109 ord @ _ => ord,
110 })
111 }
112
113 fn to_offset(&self, content: &MultiBufferSnapshot) -> Range<usize> {
114 self.start.to_offset(&content)..self.end.to_offset(&content)
115 }
116
117 fn to_point(&self, content: &MultiBufferSnapshot) -> Range<Point> {
118 self.start.to_point(&content)..self.end.to_point(&content)
119 }
120}