Skip to repository content132 lines · 4.8 KB · rust
tenant.openagents/omega
No repository description is available.
OpenAgents Git authority 2026-07-28T04:59:30.826Z Public web read
NIP-34 coordinate
30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omegaMaintainersHidden in public view
References2 branches · 1 tag
Read-only clone
git clone https://openagents.com/git/tenant.openagents/omega.gitBrowse files
row_chunk.rs
1//! A row chunk is an exclusive range of rows, [`BufferRow`] within a buffer of a certain version, [`Global`].
2//! All but the last chunk are of a constant, given size.
3
4use std::{collections::BTreeSet, ops::Range};
5
6use collections::HashMap;
7use parking_lot::Mutex;
8use text::{Anchor, Point};
9use util::RangeExt;
10
11use crate::BufferRow;
12
13/// An range of rows, exclusive as [`lsp::Range`] and
14/// <https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#range>
15/// denote.
16///
17/// Represents an area in a text editor, adjacent to other ones.
18/// Together, chunks form entire document at a particular version [`Global`].
19/// Each chunk is queried for inlays as `(start_row, 0)..(end_exclusive, 0)` via
20/// <https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#inlayHintParams>
21///
22/// Chunk boundaries are derived arithmetically from the buffer's last row.
23/// Each chunk's anchors are computed when the chunk is first queried and memoized:
24/// resolving an anchor requires sum tree seeks, which gets expensive if done for
25/// all chunks of a large buffer at once.
26pub struct RowChunks {
27 buffer_snapshot: text::BufferSnapshot,
28 last_row: BufferRow,
29 max_rows_per_chunk: u32,
30 computed_chunks: Mutex<HashMap<usize, RowChunk>>,
31}
32
33impl std::fmt::Debug for RowChunks {
34 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35 f.debug_struct("RowChunks")
36 .field("len", &self.len())
37 .field("max_rows_per_chunk", &self.max_rows_per_chunk)
38 .field("computed_chunks", &self.computed_chunks.lock().len())
39 .finish()
40 }
41}
42
43impl RowChunks {
44 pub fn new(snapshot: &text::BufferSnapshot, max_rows_per_chunk: u32) -> Self {
45 Self {
46 last_row: snapshot.max_point().row,
47 buffer_snapshot: snapshot.clone(),
48 max_rows_per_chunk,
49 computed_chunks: Mutex::new(HashMap::default()),
50 }
51 }
52
53 pub fn version(&self) -> &clock::Global {
54 self.buffer_snapshot.version()
55 }
56
57 pub fn len(&self) -> usize {
58 (self.last_row / self.max_rows_per_chunk) as usize + 1
59 }
60
61 pub fn applicable_chunks(&self, ranges: &[Range<Point>]) -> impl Iterator<Item = RowChunk> {
62 let last_chunk_id = self.len() - 1;
63 let mut chunk_ids = BTreeSet::new();
64 for point_range in ranges {
65 // Be lenient and yield multiple chunks if they "touch" the exclusive part of the range.
66 // This will result in LSP hints [re-]queried for more ranges, but also more hints already visible when scrolling around.
67 let row_range = point_range.start.row..point_range.end.row + 1;
68 let first_id = (point_range.start.row.div_ceil(self.max_rows_per_chunk) as usize)
69 .saturating_sub(1);
70 let last_id =
71 ((point_range.end.row / self.max_rows_per_chunk) as usize).min(last_chunk_id);
72 for id in first_id..=last_id {
73 if self.chunk_row_range(id).to_inclusive().overlaps(&row_range) {
74 chunk_ids.insert(id);
75 }
76 }
77 }
78 chunk_ids.into_iter().map(|id| self.chunk(id))
79 }
80
81 pub fn previous_chunk(&self, chunk: RowChunk) -> Option<RowChunk> {
82 if chunk.id == 0 || chunk.id > self.len() {
83 None
84 } else {
85 Some(self.chunk(chunk.id - 1))
86 }
87 }
88
89 fn chunk_row_range(&self, id: usize) -> Range<BufferRow> {
90 let start = id as u32 * self.max_rows_per_chunk;
91 start..(start + self.max_rows_per_chunk).min(self.last_row)
92 }
93
94 fn chunk(&self, id: usize) -> RowChunk {
95 *self.computed_chunks.lock().entry(id).or_insert_with(|| {
96 let row_range = self.chunk_row_range(id);
97 let start = Point::new(row_range.start, 0);
98 let end = if id == self.len() - 1 {
99 Point::new(row_range.end, self.buffer_snapshot.line_len(row_range.end))
100 } else {
101 Point::new(row_range.end, 0)
102 };
103 RowChunk {
104 id,
105 start: row_range.start,
106 end_exclusive: row_range.end,
107 start_anchor: self.buffer_snapshot.anchor_before(start),
108 end_anchor: self.buffer_snapshot.anchor_after(end),
109 }
110 })
111 }
112}
113
114#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
115pub struct RowChunk {
116 pub id: usize,
117 pub start: BufferRow,
118 pub end_exclusive: BufferRow,
119 pub start_anchor: Anchor,
120 pub end_anchor: Anchor,
121}
122
123impl RowChunk {
124 pub fn row_range(&self) -> Range<BufferRow> {
125 self.start..self.end_exclusive
126 }
127
128 pub fn anchor_range(&self) -> Range<Anchor> {
129 self.start_anchor..self.end_anchor
130 }
131}
132