hax_frontend_exporter/
comments.rs1use crate::prelude::*;
2use rustc_lexer::TokenKind;
3use std::fs;
4
5pub fn comments_of_file(path: PathBuf) -> std::io::Result<Vec<(Span, String)>> {
8 fn clean_comment(comment: &str) -> &str {
9 let comment = if let Some(comment) = comment.strip_prefix("/*") {
10 comment
11 .strip_suffix("*/")
12 .expect("A comment that starts with `/*` should always ends with `*/`")
13 } else {
14 comment
15 .strip_prefix("//")
16 .expect("A comment has to start with `//` or `/*`")
17 };
18 comment.strip_prefix("!").unwrap_or(comment)
19 }
20 let source = &fs::read_to_string(&path)?;
21
22 let mut comments = vec![];
23 let (mut pos, mut line, mut col) = (0, 0, 0);
24 for token in rustc_lexer::tokenize(source, rustc_lexer::FrontmatterAllowed::Yes) {
25 let len = token.len as usize;
26 let sub = &source[pos..(pos + len)];
27 let lo = Loc { line, col };
28 line += sub.chars().filter(|c| matches!(c, '\n')).count();
29 pos += len;
30 if lo.line != line {
31 col = sub.chars().rev().take_while(|c| !matches!(c, '\n')).count();
32 } else {
33 col += len;
34 }
35
36 if let TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } = token.kind {
37 if !sub.starts_with("///") && !sub.starts_with("/**") {
38 let span = Span {
39 lo,
40 hi: Loc { line, col },
41 filename: FileName::Real(RealFileName::LocalPath(path.clone())),
42 rust_span_data: None,
43 };
44 comments.push((span, clean_comment(sub).to_string()));
45 }
46 }
47 }
48 Ok(comments)
49}