Skip to main content

mago_syntax/comments/
mod.rs

1use crate::ast::Trivia;
2use crate::ast::TriviaKind;
3
4pub mod docblock;
5
6/// Splits a comment into lines, preserving the offset of each line from the start of the trivia.
7///
8/// This is crucial for calculating the precise `Span` of pragmas within a comment.
9///
10/// # Returns
11///
12/// A `Vec` of `(usize, &str)` tuples, where the `usize` is the byte offset of the
13/// line from the start of the entire trivia text (including `/**`, `//`, etc.),
14/// and the `&str` is the cleaned line content.
15#[inline]
16#[must_use]
17pub fn comment_lines<'arena>(trivia: &Trivia<'arena>) -> Vec<(u32, &'arena str)> {
18    let full_text = trivia.value;
19    let (content_start_offset, content_end_offset) = match trivia.kind {
20        TriviaKind::MultiLineComment => (2u32, full_text.len() as u32 - 2),
21        TriviaKind::DocBlockComment => (3u32, full_text.len() as u32 - 2),
22        TriviaKind::SingleLineComment => (2u32, full_text.len() as u32),
23        TriviaKind::HashComment => (1u32, full_text.len() as u32),
24        TriviaKind::WhiteSpace => return vec![],
25    };
26
27    // Handle empty comments like `/**/` to prevent slicing panics.
28    if content_start_offset >= content_end_offset {
29        return vec![];
30    }
31
32    let content = &full_text[content_start_offset as usize..content_end_offset as usize];
33
34    let mut lines = Vec::new();
35
36    for line in content.lines() {
37        // Calculate the offset of the line relative to the start of the `content` slice.
38        let relative_line_offset = (line.as_ptr() as u32) - (content.as_ptr() as u32);
39        // Add the initial offset to get the position from the start of the entire trivia string.
40        let offset_in_trivia = content_start_offset + relative_line_offset;
41
42        let cleaned_line = if trivia.kind.is_block_comment() {
43            if let Some(stripped) = line.trim_start().strip_prefix('*') { stripped.trim_start() } else { line }
44        } else {
45            line
46        };
47
48        // Calculate how many bytes were trimmed from the start of the original line slice.
49        let trimmed_bytes = (cleaned_line.as_ptr() as u32) - (line.as_ptr() as u32);
50        let final_offset = offset_in_trivia + trimmed_bytes;
51
52        lines.push((final_offset, cleaned_line));
53    }
54
55    lines
56}