mago_syntax/comments/
mod.rs

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