Skip to main content

ocelot_base/
source_excerpt.rs

1use crate::file_path::FilePath;
2use crate::shared_string::SharedString;
3use crate::source_annotation::SourceAnnotation;
4
5/// One rendered source line plus inline annotations.
6#[derive(Debug, Clone, PartialEq, Eq)]
7pub struct SourceExcerpt {
8    /// Logical path for the excerpted source line.
9    pub file_path: FilePath,
10    /// One-based line number in the source file.
11    pub line_number: usize,
12    /// Full source line text.
13    pub source_line: SharedString,
14    /// Span annotations attached to this line.
15    pub annotations: Vec<SourceAnnotation>,
16}
17
18impl SourceExcerpt {
19    /// Creates a source excerpt from its file path, line number, and source text.
20    pub fn new(
21        file_path: impl Into<FilePath>,
22        line_number: usize,
23        source_line: impl Into<SharedString>,
24    ) -> Self {
25        Self {
26            file_path: file_path.into(),
27            line_number,
28            source_line: source_line.into(),
29            annotations: Vec::new(),
30        }
31    }
32
33    /// Returns a copy of this excerpt with one appended annotation.
34    pub fn with_annotation(mut self, annotation: SourceAnnotation) -> Self {
35        self.annotations.push(annotation);
36        self
37    }
38}
39
40#[cfg(test)]
41mod tests {
42    use super::SourceExcerpt;
43    use crate::source_annotation::SourceAnnotation;
44    use crate::span::Span;
45
46    #[test]
47    fn source_excerpt_tracks_annotations() {
48        let excerpt = SourceExcerpt::new("examples/test.ocelot", 3, "println(value);")
49            .with_annotation(SourceAnnotation::new(Span::new(8, 13), "unknown name"));
50
51        assert_eq!(excerpt.file_path.as_str(), "examples/test.ocelot");
52        assert_eq!(excerpt.line_number, 3);
53        assert_eq!(excerpt.source_line, "println(value);");
54        assert_eq!(excerpt.annotations.len(), 1);
55        assert_eq!(excerpt.annotations[0].span, Span::new(8, 13));
56        assert_eq!(excerpt.annotations[0].message, "unknown name");
57    }
58}