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::ops::Range;
5
6use clock::Global;
7use text::OffsetRangeExt as _;
8
9use crate::BufferRow;
10
11/// An range of rows, exclusive as [`lsp::Range`] and
12/// <https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#range>
13/// denote.
14///
15/// Represents an area in a text editor, adjacent to other ones.
16/// Together, chunks form entire document at a particular version [`Global`].
17/// Each chunk is queried for inlays as `(start_row, 0)..(end_exclusive, 0)` via
18/// <https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#inlayHintParams>
19pub struct RowChunks {
20 pub snapshot: text::BufferSnapshot,
21 pub chunks: Vec<RowChunk>,
22}
23
24impl std::fmt::Debug for RowChunks {
25 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26 f.debug_struct("RowChunks")
27 .field("version", self.snapshot.version())
28 .field("chunks", &self.chunks)
29 .finish()
30 }
31}
32
33impl RowChunks {
34 pub fn new(snapshot: text::BufferSnapshot, max_rows_per_chunk: u32) -> Self {
35 let buffer_point_range = (0..snapshot.len()).to_point(&snapshot);
36 let last_row = buffer_point_range.end.row;
37 let chunks = (buffer_point_range.start.row..=last_row)
38 .step_by(max_rows_per_chunk as usize)
39 .enumerate()
40 .map(|(id, chunk_start)| RowChunk {
41 id,
42 start: chunk_start,
43 end_exclusive: (chunk_start + max_rows_per_chunk).min(last_row),
44 })
45 .collect();
46 Self { snapshot, chunks }
47 }
48
49 pub fn version(&self) -> &Global {
50 self.snapshot.version()
51 }
52
53 pub fn len(&self) -> usize {
54 self.chunks.len()
55 }
56
57 pub fn applicable_chunks(
58 &self,
59 ranges: &[Range<text::Anchor>],
60 ) -> impl Iterator<Item = RowChunk> {
61 let row_ranges = ranges
62 .iter()
63 .map(|range| range.to_point(&self.snapshot))
64 .map(|point_range| point_range.start.row..=point_range.end.row)
65 .collect::<Vec<_>>();
66 self.chunks
67 .iter()
68 .filter(move |chunk| -> bool {
69 // Be lenient and yield multiple chunks if they "touch" the exclusive part of the range.
70 // This will result in LSP hints [re-]queried for more ranges, but also more hints already visible when scrolling around.
71 let chunk_range = chunk.start..=chunk.end_exclusive;
72 row_ranges.iter().any(|row_range| {
73 chunk_range.contains(&row_range.start())
74 || chunk_range.contains(&row_range.end())
75 })
76 })
77 .copied()
78 }
79}
80
81#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
82pub struct RowChunk {
83 pub id: usize,
84 pub start: BufferRow,
85 pub end_exclusive: BufferRow,
86}