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