oak_core/source/
view.rs

1use crate::{SourceText, source::Source};
2use lsp_types::Position;
3use std::range::Range;
4
5/// A view into a portion of source text.
6///
7/// This struct represents a slice or window into a larger source text,
8/// allowing parsers to work with specific sections of code while maintaining
9/// proper position tracking and coordinate conversion.
10#[derive(Clone, Debug, PartialEq, Eq, Hash)]
11pub struct SourceView<'view> {
12    pub(crate) source: &'view SourceText,
13    pub(crate) range: Range<usize>,
14}
15
16impl<'view> From<&'view SourceText> for SourceView<'view> {
17    fn from(value: &'view SourceText) -> Self {
18        Self { source: value, range: Range { start: 0, end: value.len() } }
19    }
20}
21
22impl<'view> Source for SourceView<'view> {
23    fn length(&self) -> usize {
24        self.range.end.saturating_sub(self.range.start)
25    }
26
27    fn get_text_in(&self, range: Range<usize>) -> &str {
28        // Calculate the absolute range within the underlying source
29        let start = self.range.start + range.start;
30        let end = self.range.start + range.end;
31
32        // Ensure we don't exceed the view's bounds
33        let end = end.min(self.range.end);
34
35        self.source.get_text_in((start..end).into())
36    }
37
38    fn offset_to_position(&self, offset: usize) -> Position {
39        // Convert view-relative offset to source-relative offset
40        let source_offset = self.range.start + offset;
41        self.source.offset_to_position(source_offset)
42    }
43
44    fn position_to_offset(&self, position: Position) -> usize {
45        // Convert position to source-relative offset, then adjust to view-relative
46        let source_offset = self.source.position_to_offset(position);
47        source_offset.saturating_sub(self.range.start)
48    }
49}
50
51impl<'view> SourceView<'view> {
52    /// Creates a new view into a sub-range of this view.
53    ///
54    /// This method allows creating nested views within existing views,
55    /// enabling parsers to work with increasingly specific sections of code.
56    ///
57    /// # Arguments
58    ///
59    /// * `range` - The relative range within this view to create a sub-view for
60    ///
61    /// # Returns
62    ///
63    /// A new `SourceView` representing the specified sub-range
64    pub fn view(&self, range: Range<usize>) -> Self {
65        let start = self.range.start + range.start;
66        let end = self.range.start + range.end;
67        Self { source: self.source, range: Range { start, end } }
68    }
69}