Skip to repository content

tenant.openagents/omega

No repository description is available.

OpenAgents Git authority 2026-07-28T03:56:41.037Z 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

row_chunk.rs

132 lines · 4.8 KB · rust
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
Served at tenant.openagents/omega Member data and write actions are omitted.