1use super::{Point, ToOffset};
2use crate::{rope::TextDimension, BufferSnapshot, PointUtf16, ToPoint, ToPointUtf16};
3use anyhow::Result;
4use std::{cmp::Ordering, fmt::Debug, ops::Range};
5use sum_tree::Bias;
6
7#[derive(Copy, Clone, Eq, PartialEq, Debug, Hash, Default)]
8pub struct Anchor {
9 pub timestamp: clock::Local,
10 pub offset: usize,
11 pub bias: Bias,
12 pub buffer_id: Option<u64>,
13}
14
15impl Anchor {
16 pub const MIN: Self = Self {
17 timestamp: clock::Local::MIN,
18 offset: usize::MIN,
19 bias: Bias::Left,
20 buffer_id: None,
21 };
22
23 pub const MAX: Self = Self {
24 timestamp: clock::Local::MAX,
25 offset: usize::MAX,
26 bias: Bias::Right,
27 buffer_id: None,
28 };
29
30 pub fn cmp(&self, other: &Anchor, buffer: &BufferSnapshot) -> Ordering {
31 let fragment_id_comparison = if self.timestamp == other.timestamp {
32 Ordering::Equal
33 } else {
34 buffer
35 .fragment_id_for_anchor(self)
36 .cmp(buffer.fragment_id_for_anchor(other))
37 };
38
39 fragment_id_comparison
40 .then_with(|| self.offset.cmp(&other.offset))
41 .then_with(|| self.bias.cmp(&other.bias))
42 }
43
44 pub fn min(&self, other: &Self, buffer: &BufferSnapshot) -> Self {
45 if self.cmp(other, buffer).is_le() {
46 *self
47 } else {
48 *other
49 }
50 }
51
52 pub fn max(&self, other: &Self, buffer: &BufferSnapshot) -> Self {
53 if self.cmp(other, buffer).is_ge() {
54 *self
55 } else {
56 *other
57 }
58 }
59
60 pub fn bias(&self, bias: Bias, buffer: &BufferSnapshot) -> Anchor {
61 if bias == Bias::Left {
62 self.bias_left(buffer)
63 } else {
64 self.bias_right(buffer)
65 }
66 }
67
68 pub fn bias_left(&self, buffer: &BufferSnapshot) -> Anchor {
69 if self.bias == Bias::Left {
70 *self
71 } else {
72 buffer.anchor_before(self)
73 }
74 }
75
76 pub fn bias_right(&self, buffer: &BufferSnapshot) -> Anchor {
77 if self.bias == Bias::Right {
78 *self
79 } else {
80 buffer.anchor_after(self)
81 }
82 }
83
84 pub fn summary<D>(&self, content: &BufferSnapshot) -> D
85 where
86 D: TextDimension,
87 {
88 content.summary_for_anchor(self)
89 }
90}
91
92pub trait OffsetRangeExt {
93 fn to_offset(&self, snapshot: &BufferSnapshot) -> Range<usize>;
94 fn to_point(&self, snapshot: &BufferSnapshot) -> Range<Point>;
95 fn to_point_utf16(&self, snapshot: &BufferSnapshot) -> Range<PointUtf16>;
96}
97
98impl<T> OffsetRangeExt for Range<T>
99where
100 T: ToOffset,
101{
102 fn to_offset(&self, snapshot: &BufferSnapshot) -> Range<usize> {
103 self.start.to_offset(snapshot)..self.end.to_offset(snapshot)
104 }
105
106 fn to_point(&self, snapshot: &BufferSnapshot) -> Range<Point> {
107 self.start.to_offset(snapshot).to_point(snapshot)
108 ..self.end.to_offset(snapshot).to_point(snapshot)
109 }
110
111 fn to_point_utf16(&self, snapshot: &BufferSnapshot) -> Range<PointUtf16> {
112 self.start.to_offset(snapshot).to_point_utf16(snapshot)
113 ..self.end.to_offset(snapshot).to_point_utf16(snapshot)
114 }
115}
116
117pub trait AnchorRangeExt {
118 fn cmp(&self, b: &Range<Anchor>, buffer: &BufferSnapshot) -> Result<Ordering>;
119}
120
121impl AnchorRangeExt for Range<Anchor> {
122 fn cmp(&self, other: &Range<Anchor>, buffer: &BufferSnapshot) -> Result<Ordering> {
123 Ok(match self.start.cmp(&other.start, buffer) {
124 Ordering::Equal => other.end.cmp(&self.end, buffer),
125 ord => ord,
126 })
127 }
128}