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) buffer_id: 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: 0,
21 excerpt_id: ExcerptId::min(),
22 text_anchor: text::Anchor::min(),
23 }
24 }
25
26 pub fn max() -> Self {
27 Self {
28 buffer_id: 0,
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 {
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 buffer_id: self.buffer_id,
61 excerpt_id: self.excerpt_id.clone(),
62 text_anchor: self.text_anchor.bias_left(buffer_snapshot),
63 };
64 }
65 }
66 self.clone()
67 }
68
69 pub fn bias_right(&self, snapshot: &MultiBufferSnapshot) -> Anchor {
70 if self.text_anchor.bias != Bias::Right {
71 if let Some(buffer_snapshot) = snapshot.buffer_snapshot_for_excerpt(&self.excerpt_id) {
72 return Self {
73 buffer_id: self.buffer_id,
74 excerpt_id: self.excerpt_id.clone(),
75 text_anchor: self.text_anchor.bias_right(buffer_snapshot),
76 };
77 }
78 }
79 self.clone()
80 }
81
82 pub fn summary<D>(&self, snapshot: &MultiBufferSnapshot) -> D
83 where
84 D: TextDimension + Ord + Sub<D, Output = D>,
85 {
86 snapshot.summary_for_anchor(self)
87 }
88}
89
90impl ToOffset for Anchor {
91 fn to_offset<'a>(&self, snapshot: &MultiBufferSnapshot) -> usize {
92 self.summary(snapshot)
93 }
94}
95
96impl ToPoint for Anchor {
97 fn to_point<'a>(&self, snapshot: &MultiBufferSnapshot) -> Point {
98 self.summary(snapshot)
99 }
100}
101
102pub trait AnchorRangeExt {
103 fn cmp(&self, b: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> Result<Ordering>;
104 fn to_offset(&self, content: &MultiBufferSnapshot) -> Range<usize>;
105 fn to_point(&self, content: &MultiBufferSnapshot) -> Range<Point>;
106}
107
108impl AnchorRangeExt for Range<Anchor> {
109 fn cmp(&self, other: &Range<Anchor>, buffer: &MultiBufferSnapshot) -> Result<Ordering> {
110 Ok(match self.start.cmp(&other.start, buffer)? {
111 Ordering::Equal => other.end.cmp(&self.end, buffer)?,
112 ord @ _ => ord,
113 })
114 }
115
116 fn to_offset(&self, content: &MultiBufferSnapshot) -> Range<usize> {
117 self.start.to_offset(&content)..self.end.to_offset(&content)
118 }
119
120 fn to_point(&self, content: &MultiBufferSnapshot) -> Range<Point> {
121 self.start.to_point(&content)..self.end.to_point(&content)
122 }
123}