1use crate::{rope::TextDimension, Snapshot};
2
3use super::{Buffer, ToOffset};
4use anyhow::Result;
5use std::{cmp::Ordering, fmt::Debug, ops::Range};
6use sum_tree::Bias;
7
8#[derive(Clone, Eq, PartialEq, Debug, Hash)]
9pub enum Anchor {
10 Min,
11 Insertion {
12 timestamp: clock::Local,
13 offset: usize,
14 bias: Bias,
15 },
16 Max,
17}
18
19impl Anchor {
20 pub fn min() -> Self {
21 Self::Min
22 }
23
24 pub fn max() -> Self {
25 Self::Max
26 }
27
28 pub fn cmp<'a>(&self, other: &Anchor, buffer: &Snapshot) -> Result<Ordering> {
29 match (self, other) {
30 (Self::Min, Self::Min) => Ok(Ordering::Equal),
31 (Self::Min, _) => Ok(Ordering::Less),
32 (_, Self::Min) => Ok(Ordering::Greater),
33 (Self::Max, Self::Max) => Ok(Ordering::Equal),
34 (Self::Max, _) => Ok(Ordering::Greater),
35 (_, Self::Max) => Ok(Ordering::Less),
36 (
37 Self::Insertion {
38 timestamp: lhs_id,
39 bias: lhs_bias,
40 offset: lhs_offset,
41 },
42 Self::Insertion {
43 timestamp: rhs_id,
44 bias: rhs_bias,
45 offset: rhs_offset,
46 },
47 ) => {
48 let offset_comparison = if lhs_id == rhs_id {
49 lhs_offset.cmp(&rhs_offset)
50 } else {
51 buffer
52 .full_offset_for_anchor(self)
53 .cmp(&buffer.full_offset_for_anchor(other))
54 };
55
56 Ok(offset_comparison.then_with(|| lhs_bias.cmp(&rhs_bias)))
57 }
58 }
59 }
60
61 pub fn bias_left(&self, buffer: &Buffer) -> Anchor {
62 match self {
63 Anchor::Min => Anchor::Min,
64 Anchor::Insertion { bias, .. } => {
65 if *bias == Bias::Left {
66 self.clone()
67 } else {
68 buffer.anchor_before(self)
69 }
70 }
71 Anchor::Max => buffer.anchor_before(self),
72 }
73 }
74
75 pub fn bias_right(&self, buffer: &Buffer) -> Anchor {
76 match self {
77 Anchor::Min => buffer.anchor_after(self),
78 Anchor::Insertion { bias, .. } => {
79 if *bias == Bias::Right {
80 self.clone()
81 } else {
82 buffer.anchor_after(self)
83 }
84 }
85 Anchor::Max => Anchor::Max,
86 }
87 }
88
89 pub fn summary<'a, D>(&self, content: &'a Snapshot) -> D
90 where
91 D: TextDimension<'a>,
92 {
93 content.summary_for_anchor(self)
94 }
95}
96
97pub trait AnchorRangeExt {
98 fn cmp(&self, b: &Range<Anchor>, buffer: &Snapshot) -> Result<Ordering>;
99 fn to_offset(&self, content: &Snapshot) -> Range<usize>;
100}
101
102impl AnchorRangeExt for Range<Anchor> {
103 fn cmp(&self, other: &Range<Anchor>, buffer: &Snapshot) -> Result<Ordering> {
104 Ok(match self.start.cmp(&other.start, buffer)? {
105 Ordering::Equal => other.end.cmp(&self.end, buffer)?,
106 ord @ _ => ord,
107 })
108 }
109
110 fn to_offset(&self, content: &Snapshot) -> Range<usize> {
111 self.start.to_offset(&content)..self.end.to_offset(&content)
112 }
113}