Skip to repository content

tenant.openagents/omega

No repository description is available.

OpenAgents Git authority 2026-07-28T02:36:36.183Z Public web read
NIP-34 coordinate30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omega
MaintainersHidden in public view
References2 branches · 1 tag
Read-only clonegit clone https://openagents.com/git/tenant.openagents/omega.git
Browse files

anchor.rs

250 lines · 8.2 KB · rust
1use crate::{
2    BufferId, BufferSnapshot, Point, PointUtf16, TextDimension, ToOffset, ToPoint, ToPointUtf16,
3    locator::Locator,
4};
5use std::{cmp::Ordering, fmt::Debug, ops::Range};
6use sum_tree::{Bias, Dimensions};
7
8/// A timestamped position in a buffer.
9#[doc(alias = "TextAnchor")]
10#[derive(Copy, Clone, Eq, PartialEq, Hash)]
11pub struct Anchor {
12    // /// The timestamp of the operation that inserted the text
13    // /// in which this anchor is located.
14    // pub(crate) timestamp: clock::Lamport,
15    // we store the replica id and sequence number of the timestamp inline
16    // to avoid the alignment of our fields from increasing the size of this struct
17    // This saves 8 bytes, by allowing replica id, value and bias to occupy the padding
18    pub(crate) timestamp_replica_id: clock::ReplicaId,
19    pub(crate) timestamp_value: clock::Seq,
20
21    /// The byte offset into the text inserted in the operation
22    /// at `timestamp`.
23    pub offset: u32,
24    /// Whether this anchor stays attached to the character *before* or *after*
25    /// the offset.
26    pub bias: Bias,
27    pub buffer_id: BufferId,
28}
29
30impl Debug for Anchor {
31    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32        if self.is_min() {
33            return write!(f, "Anchor::min({:?})", self.buffer_id);
34        }
35        if self.is_max() {
36            return write!(f, "Anchor::max({:?})", self.buffer_id);
37        }
38
39        f.debug_struct("Anchor")
40            .field("timestamp", &self.timestamp())
41            .field("offset", &self.offset)
42            .field("bias", &self.bias)
43            .field("buffer_id", &self.buffer_id)
44            .finish()
45    }
46}
47
48impl Anchor {
49    pub fn new(timestamp: clock::Lamport, offset: u32, bias: Bias, buffer_id: BufferId) -> Self {
50        Self {
51            timestamp_replica_id: timestamp.replica_id,
52            timestamp_value: timestamp.value,
53            offset,
54            bias,
55            buffer_id,
56        }
57    }
58
59    pub fn min_for_buffer(buffer_id: BufferId) -> Self {
60        Self {
61            timestamp_replica_id: clock::Lamport::MIN.replica_id,
62            timestamp_value: clock::Lamport::MIN.value,
63            offset: u32::MIN,
64            bias: Bias::Left,
65            buffer_id,
66        }
67    }
68
69    pub fn max_for_buffer(buffer_id: BufferId) -> Self {
70        Self {
71            timestamp_replica_id: clock::Lamport::MAX.replica_id,
72            timestamp_value: clock::Lamport::MAX.value,
73            offset: u32::MAX,
74            bias: Bias::Right,
75            buffer_id,
76        }
77    }
78
79    pub fn min_min_range_for_buffer(buffer_id: BufferId) -> std::ops::Range<Self> {
80        let min = Self::min_for_buffer(buffer_id);
81        min..min
82    }
83    pub fn max_max_range_for_buffer(buffer_id: BufferId) -> std::ops::Range<Self> {
84        let max = Self::max_for_buffer(buffer_id);
85        max..max
86    }
87    pub fn min_max_range_for_buffer(buffer_id: BufferId) -> std::ops::Range<Self> {
88        Self::min_for_buffer(buffer_id)..Self::max_for_buffer(buffer_id)
89    }
90
91    pub fn cmp(&self, other: &Anchor, buffer: &BufferSnapshot) -> Ordering {
92        let fragment_id_comparison = if self.timestamp() == other.timestamp() {
93            Ordering::Equal
94        } else {
95            buffer
96                .fragment_id_for_anchor(self)
97                .cmp(buffer.fragment_id_for_anchor(other))
98        };
99
100        fragment_id_comparison
101            .then_with(|| self.offset.cmp(&other.offset))
102            .then_with(|| self.bias.cmp(&other.bias))
103    }
104
105    pub fn min<'a>(&'a self, other: &'a Self, buffer: &BufferSnapshot) -> &'a Self {
106        if self.cmp(other, buffer).is_le() {
107            self
108        } else {
109            other
110        }
111    }
112
113    pub fn max<'a>(&'a self, other: &'a Self, buffer: &BufferSnapshot) -> &'a Self {
114        if self.cmp(other, buffer).is_ge() {
115            self
116        } else {
117            other
118        }
119    }
120
121    pub fn bias(&self, bias: Bias, buffer: &BufferSnapshot) -> Anchor {
122        match bias {
123            Bias::Left => self.bias_left(buffer),
124            Bias::Right => self.bias_right(buffer),
125        }
126    }
127
128    pub fn bias_left(&self, buffer: &BufferSnapshot) -> Anchor {
129        match self.bias {
130            Bias::Left => *self,
131            Bias::Right => buffer.anchor_before(self),
132        }
133    }
134
135    pub fn bias_right(&self, buffer: &BufferSnapshot) -> Anchor {
136        match self.bias {
137            Bias::Left => buffer.anchor_after(self),
138            Bias::Right => *self,
139        }
140    }
141
142    pub fn summary<D>(&self, content: &BufferSnapshot) -> D
143    where
144        D: TextDimension,
145    {
146        content.summary_for_anchor(self)
147    }
148
149    /// Returns true when the [`Anchor`] is located inside a visible fragment.
150    pub fn is_valid(&self, buffer: &BufferSnapshot) -> bool {
151        if self.is_min() || self.is_max() {
152            true
153        } else if self.buffer_id != buffer.remote_id {
154            false
155        } else {
156            let Some(fragment_id) = buffer.try_fragment_id_for_anchor(self) else {
157                return false;
158            };
159            let (.., item) = buffer
160                .fragments
161                .find::<Dimensions<Option<&Locator>, usize>, _>(
162                    &None,
163                    &Some(fragment_id),
164                    Bias::Left,
165                );
166            item.is_some_and(|fragment| fragment.visible)
167        }
168    }
169
170    pub fn is_min(&self) -> bool {
171        self.timestamp() == clock::Lamport::MIN
172            && self.offset == u32::MIN
173            && self.bias == Bias::Left
174    }
175
176    pub fn is_max(&self) -> bool {
177        self.timestamp() == clock::Lamport::MAX
178            && self.offset == u32::MAX
179            && self.bias == Bias::Right
180    }
181
182    #[inline]
183    pub fn timestamp(&self) -> clock::Lamport {
184        clock::Lamport {
185            replica_id: self.timestamp_replica_id,
186            value: self.timestamp_value,
187        }
188    }
189
190    pub fn opaque_id(&self) -> [u8; 20] {
191        let mut bytes = [0u8; 20];
192        let buffer_id: u64 = self.buffer_id.into();
193        bytes[0..8].copy_from_slice(&buffer_id.to_le_bytes());
194        bytes[8..12].copy_from_slice(&self.offset.to_le_bytes());
195        bytes[12..16].copy_from_slice(&self.timestamp_value.to_le_bytes());
196        let replica_id = self.timestamp_replica_id.as_u16();
197        bytes[16..18].copy_from_slice(&replica_id.to_le_bytes());
198        bytes[18] = self.bias as u8;
199        bytes
200    }
201}
202
203pub trait OffsetRangeExt {
204    fn to_offset(&self, snapshot: &BufferSnapshot) -> Range<usize>;
205    fn to_point(&self, snapshot: &BufferSnapshot) -> Range<Point>;
206    fn to_point_utf16(&self, snapshot: &BufferSnapshot) -> Range<PointUtf16>;
207}
208
209impl<T> OffsetRangeExt for Range<T>
210where
211    T: ToOffset,
212{
213    fn to_offset(&self, snapshot: &BufferSnapshot) -> Range<usize> {
214        self.start.to_offset(snapshot)..self.end.to_offset(snapshot)
215    }
216
217    fn to_point(&self, snapshot: &BufferSnapshot) -> Range<Point> {
218        self.start.to_offset(snapshot).to_point(snapshot)
219            ..self.end.to_offset(snapshot).to_point(snapshot)
220    }
221
222    fn to_point_utf16(&self, snapshot: &BufferSnapshot) -> Range<PointUtf16> {
223        self.start.to_offset(snapshot).to_point_utf16(snapshot)
224            ..self.end.to_offset(snapshot).to_point_utf16(snapshot)
225    }
226}
227
228pub trait AnchorRangeExt {
229    fn cmp(&self, b: &Range<Anchor>, buffer: &BufferSnapshot) -> Ordering;
230    fn overlaps(&self, b: &Range<Anchor>, buffer: &BufferSnapshot) -> bool;
231    fn contains_anchor(&self, b: Anchor, buffer: &BufferSnapshot) -> bool;
232}
233
234impl AnchorRangeExt for Range<Anchor> {
235    fn cmp(&self, other: &Range<Anchor>, buffer: &BufferSnapshot) -> Ordering {
236        match self.start.cmp(&other.start, buffer) {
237            Ordering::Equal => other.end.cmp(&self.end, buffer),
238            ord => ord,
239        }
240    }
241
242    fn overlaps(&self, other: &Range<Anchor>, buffer: &BufferSnapshot) -> bool {
243        self.start.cmp(&other.end, buffer).is_lt() && other.start.cmp(&self.end, buffer).is_lt()
244    }
245
246    fn contains_anchor(&self, other: Anchor, buffer: &BufferSnapshot) -> bool {
247        self.start.cmp(&other, buffer).is_le() && self.end.cmp(&other, buffer).is_ge()
248    }
249}
250
Served at tenant.openagents/omega Member data and write actions are omitted.