1use crate::Point;
2
3use super::{Buffer, Content};
4use anyhow::Result;
5use std::{
6 cmp::Ordering,
7 fmt::{Debug, Formatter},
8 ops::Range,
9};
10use sum_tree::Bias;
11
12#[derive(Clone, Eq, PartialEq, Debug, Hash)]
13pub struct Anchor {
14 pub offset: usize,
15 pub bias: Bias,
16 pub version: clock::Global,
17}
18
19#[derive(Clone)]
20pub struct AnchorMap<T> {
21 pub(crate) version: clock::Global,
22 pub(crate) entries: Vec<((usize, Bias), T)>,
23}
24
25#[derive(Clone)]
26pub struct AnchorSet(pub(crate) AnchorMap<()>);
27
28#[derive(Clone)]
29pub struct AnchorRangeMap<T> {
30 pub(crate) version: clock::Global,
31 pub(crate) entries: Vec<(Range<(usize, Bias)>, T)>,
32}
33
34#[derive(Clone)]
35pub struct AnchorRangeSet(pub(crate) AnchorRangeMap<()>);
36
37impl Anchor {
38 pub fn min() -> Self {
39 Self {
40 offset: 0,
41 bias: Bias::Left,
42 version: Default::default(),
43 }
44 }
45
46 pub fn max() -> Self {
47 Self {
48 offset: usize::MAX,
49 bias: Bias::Right,
50 version: Default::default(),
51 }
52 }
53
54 pub fn cmp<'a>(&self, other: &Anchor, buffer: impl Into<Content<'a>>) -> Result<Ordering> {
55 let buffer = buffer.into();
56
57 if self == other {
58 return Ok(Ordering::Equal);
59 }
60
61 let offset_comparison = if self.version == other.version {
62 self.offset.cmp(&other.offset)
63 } else {
64 buffer
65 .full_offset_for_anchor(self)
66 .cmp(&buffer.full_offset_for_anchor(other))
67 };
68
69 Ok(offset_comparison.then_with(|| self.bias.cmp(&other.bias)))
70 }
71
72 pub fn bias_left(&self, buffer: &Buffer) -> Anchor {
73 if self.bias == Bias::Left {
74 self.clone()
75 } else {
76 buffer.anchor_before(self)
77 }
78 }
79
80 pub fn bias_right(&self, buffer: &Buffer) -> Anchor {
81 if self.bias == Bias::Right {
82 self.clone()
83 } else {
84 buffer.anchor_after(self)
85 }
86 }
87}
88
89impl<T> AnchorMap<T> {
90 pub fn to_points<'a>(
91 &'a self,
92 content: impl Into<Content<'a>> + 'a,
93 ) -> impl Iterator<Item = (Point, &'a T)> + 'a {
94 let content = content.into();
95 content
96 .summaries_for_anchors(self)
97 .map(move |(sum, value)| (sum.lines, value))
98 }
99
100 pub fn version(&self) -> &clock::Global {
101 &self.version
102 }
103}
104
105impl AnchorSet {
106 pub fn to_points<'a>(
107 &'a self,
108 content: impl Into<Content<'a>> + 'a,
109 ) -> impl Iterator<Item = Point> + 'a {
110 self.0.to_points(content).map(move |(point, _)| point)
111 }
112}
113
114impl<T> AnchorRangeMap<T> {
115 pub fn from_raw(version: clock::Global, entries: Vec<(Range<(usize, Bias)>, T)>) -> Self {
116 Self { version, entries }
117 }
118
119 pub fn raw_entries(&self) -> &[(Range<(usize, Bias)>, T)] {
120 &self.entries
121 }
122
123 pub fn to_point_ranges<'a>(
124 &'a self,
125 content: impl Into<Content<'a>> + 'a,
126 ) -> impl Iterator<Item = (Range<Point>, &'a T)> + 'a {
127 let content = content.into();
128 content
129 .summaries_for_anchor_ranges(self)
130 .map(move |(range, value)| ((range.start.lines..range.end.lines), value))
131 }
132
133 pub fn version(&self) -> &clock::Global {
134 &self.version
135 }
136}
137
138impl<T: PartialEq> PartialEq for AnchorRangeMap<T> {
139 fn eq(&self, other: &Self) -> bool {
140 self.version == other.version && self.entries == other.entries
141 }
142}
143
144impl<T: Eq> Eq for AnchorRangeMap<T> {}
145
146impl<T: Debug> Debug for AnchorRangeMap<T> {
147 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
148 let f = f.debug_map();
149 for (range, value) in &self.entries {
150 f.key(range);
151 f.value(value);
152 }
153 f.finish()
154 }
155}
156
157impl AnchorRangeSet {
158 pub fn to_point_ranges<'a>(
159 &'a self,
160 content: impl Into<Content<'a>> + 'a,
161 ) -> impl Iterator<Item = Range<Point>> + 'a {
162 self.0.to_point_ranges(content).map(|(range, _)| range)
163 }
164
165 pub fn version(&self) -> &clock::Global {
166 self.0.version()
167 }
168}
169
170pub trait AnchorRangeExt {
171 fn cmp<'a>(&self, b: &Range<Anchor>, buffer: impl Into<Content<'a>>) -> Result<Ordering>;
172}
173
174impl AnchorRangeExt for Range<Anchor> {
175 fn cmp<'a>(&self, other: &Range<Anchor>, buffer: impl Into<Content<'a>>) -> Result<Ordering> {
176 let buffer = buffer.into();
177 Ok(match self.start.cmp(&other.start, &buffer)? {
178 Ordering::Equal => other.end.cmp(&self.end, buffer)?,
179 ord @ _ => ord,
180 })
181 }
182}