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::{ops::Range, sync::Arc};
 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>
19#[derive(Clone)]
20pub struct RowChunks {
21    pub snapshot: text::BufferSnapshot,
22    pub chunks: Arc<[RowChunk]>,
23}
24
25impl std::fmt::Debug for RowChunks {
26    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
27        f.debug_struct("RowChunks")
28            .field("version", self.snapshot.version())
29            .field("chunks", &self.chunks)
30            .finish()
31    }
32}
33
34impl RowChunks {
35    pub fn new(snapshot: text::BufferSnapshot, max_rows_per_chunk: u32) -> Self {
36        let buffer_point_range = (0..snapshot.len()).to_point(&snapshot);
37        let last_row = buffer_point_range.end.row;
38        let chunks = (buffer_point_range.start.row..=last_row)
39            .step_by(max_rows_per_chunk as usize)
40            .enumerate()
41            .map(|(id, chunk_start)| RowChunk {
42                id,
43                start: chunk_start,
44                end_exclusive: (chunk_start + max_rows_per_chunk).min(last_row),
45            })
46            .collect::<Vec<_>>();
47        Self {
48            snapshot,
49            chunks: Arc::from(chunks),
50        }
51    }
52
53    pub fn version(&self) -> &Global {
54        self.snapshot.version()
55    }
56
57    pub fn len(&self) -> usize {
58        self.chunks.len()
59    }
60
61    pub fn applicable_chunks(
62        &self,
63        ranges: &[Range<text::Anchor>],
64    ) -> impl Iterator<Item = RowChunk> {
65        let row_ranges = ranges
66            .iter()
67            .map(|range| range.to_point(&self.snapshot))
68            .map(|point_range| point_range.start.row..=point_range.end.row)
69            .collect::<Vec<_>>();
70        self.chunks
71            .iter()
72            .filter(move |chunk| -> bool {
73                // Be lenient and yield multiple chunks if they "touch" the exclusive part of the range.
74                // This will result in LSP hints [re-]queried for more ranges, but also more hints already visible when scrolling around.
75                let chunk_range = chunk.start..=chunk.end_exclusive;
76                row_ranges.iter().any(|row_range| {
77                    chunk_range.contains(&row_range.start())
78                        || chunk_range.contains(&row_range.end())
79                })
80            })
81            .copied()
82    }
83}
84
85#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
86pub struct RowChunk {
87    pub id: usize,
88    pub start: BufferRow,
89    pub end_exclusive: BufferRow,
90}