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