1use super::{ExcerptId, MultiBufferSnapshot, ToOffset, ToPoint};
2use anyhow::{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) excerpt_id: ExcerptId,
13 pub(crate) text_anchor: text::Anchor,
14}
15
16impl Anchor {
17 pub fn new(excerpt_id: ExcerptId, text_anchor: text::Anchor) -> Self {
18 Self {
19 excerpt_id,
20 text_anchor,
21 }
22 }
23
24 pub fn min() -> Self {
25 Self {
26 excerpt_id: ExcerptId::min(),
27 text_anchor: text::Anchor::min(),
28 }
29 }
30
31 pub fn max() -> Self {
32 Self {
33 excerpt_id: ExcerptId::max(),
34 text_anchor: text::Anchor::max(),
35 }
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 {
44 self.text_anchor.cmp(
45 &other.text_anchor,
46 snapshot
47 .buffer_snapshot_for_excerpt(&self.excerpt_id)
48 .ok_or_else(|| anyhow!("excerpt {:?} not found", self.excerpt_id))?,
49 )
50 }
51 } else {
52 return Ok(excerpt_id_cmp);
53 }
54 }
55
56 pub fn bias_left(&self, snapshot: &MultiBufferSnapshot) -> Anchor {
57 if self.text_anchor.bias != Bias::Left {
58 if let Some(buffer_snapshot) = snapshot.buffer_snapshot_for_excerpt(&self.excerpt_id) {
59 return Self {
60 excerpt_id: self.excerpt_id.clone(),
61 text_anchor: self.text_anchor.bias_left(buffer_snapshot),
62 };
63 }
64 }
65 self.clone()
66 }
67
68 pub fn bias_right(&self, snapshot: &MultiBufferSnapshot) -> Anchor {
69 if self.text_anchor.bias != Bias::Right {
70 if let Some(buffer_snapshot) = snapshot.buffer_snapshot_for_excerpt(&self.excerpt_id) {
71 return Self {
72 excerpt_id: self.excerpt_id.clone(),
73 text_anchor: self.text_anchor.bias_right(buffer_snapshot),
74 };
75 }
76 }
77 self.clone()
78 }
79
80 pub fn summary<D>(&self, snapshot: &MultiBufferSnapshot) -> D
81 where
82 D: TextDimension + Ord + Sub<D, Output = D>,
83 {
84 snapshot.summary_for_anchor(self)
85 }
86}
87
88impl ToOffset for Anchor {
89 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
90 self.summary(snapshot)
91 }
92}
93
94impl ToPoint for Anchor {
95 fn to_point<'a>(&self, snapshot: &MultiBufferSnapshot) -> Point {
96 self.summary(snapshot)
97 }
98}
99
100pub trait AnchorRangeExt {
101 fn cmp(&self, b: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> Result<Ordering>;
102 fn to_offset(&self, content: &MultiBufferSnapshot) -> Range<usize>;
103 fn to_point(&self, content: &MultiBufferSnapshot) -> Range<Point>;
104}
105
106impl AnchorRangeExt for Range<Anchor> {
107 fn cmp(&self, other: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> Result<Ordering> {
108 Ok(match self.start.cmp(&other.start, buffer)? {
109 Ordering::Equal => other.end.cmp(&self.end, buffer)?,
110 ord @ _ => ord,
111 })
112 }
113
114 fn to_offset(&self, content: &MultiBufferSnapshot) -> Range<usize> {
115 self.start.to_offset(&content)..self.end.to_offset(&content)
116 }
117
118 fn to_point(&self, content: &MultiBufferSnapshot) -> Range<Point> {
119 self.start.to_point(&content)..self.end.to_point(&content)
120 }
121}