use rustc_lexer::{FrontmatterAllowed, TokenKind, tokenize};
use super::UseStmt;
use super::config::Style;
pub(super) fn count_blank_lines(gap: &str) -> usize {
let lines: Vec<&str> = gap.split('\n').collect();
if lines.len() <= 2 {
return 0;
}
let block_comments = block_comment_ranges(gap);
let mut count = 0;
let mut offset = 0;
for (index, line) in lines.iter().enumerate() {
let line_start = offset;
offset += line.len() + 1;
if index == 0 || index == lines.len() - 1 {
continue;
}
if !line.trim().is_empty() {
continue;
}
let inside_block_comment = block_comments
.iter()
.any(|&(start, end)| line_start >= start && line_start < end);
if !inside_block_comment {
count += 1;
}
}
count
}
fn block_comment_ranges(text: &str) -> Vec<(usize, usize)> {
let mut ranges = Vec::new();
let mut offset = 0;
for token in tokenize(text, FrontmatterAllowed::No) {
let length = token.len as usize;
if matches!(token.kind, TokenKind::BlockComment { .. }) {
ranges.push((offset, offset + length));
}
offset += length;
}
ranges
}
pub(super) fn is_compliant(
style: Style,
blank_line_count: usize,
stmts: &[UseStmt<'_>],
blanks: &[usize],
) -> bool {
match style {
Style::SingleGroup => single_group_compliant(blanks),
Style::Grouped => grouped_compliant(blank_line_count, stmts, blanks),
}
}
fn single_group_compliant(blanks: &[usize]) -> bool {
blanks.iter().all(|&blanks| blanks == 0)
}
fn grouped_compliant(blank_line_count: usize, stmts: &[UseStmt<'_>], blanks: &[usize]) -> bool {
stmts
.windows(2)
.zip(blanks)
.all(|(pair, &blanks)| match pair[0].rank.cmp(&pair[1].rank) {
std::cmp::Ordering::Equal => blanks == 0,
std::cmp::Ordering::Less => blanks == blank_line_count,
std::cmp::Ordering::Greater => false,
})
}