fn is_comment_line(trimmed: &str) -> bool {
trimmed.starts_with("///")
|| trimmed.starts_with("//!")
|| trimmed.starts_with("//")
|| trimmed.starts_with("/*")
|| trimmed.starts_with("*")
}
pub fn find_line_of_str(content: &str, target: &str) -> usize {
for (i, line) in content.lines().enumerate() {
let trimmed = line.trim();
if is_comment_line(trimmed) {
continue;
}
if line.contains(target) {
return i + 1;
}
}
1
}
pub fn find_line_of_str_non_import(content: &str, target: &str) -> usize {
for (i, line) in content.lines().enumerate() {
let trimmed = line.trim();
if is_comment_line(trimmed) || trimmed.starts_with("use ") {
continue;
}
if line.contains(target) {
return i + 1;
}
}
1
}
pub fn count_non_comment_matches(content: &str, target: &str) -> usize {
let mut count = 0;
for line in content.lines() {
let trimmed = line.trim();
if is_comment_line(trimmed) {
continue;
}
count += line.matches(target).count();
}
count
}
pub fn get_position_from_content(content: &str, byte_offset: usize) -> (usize, usize) {
let mut line = 1;
let mut col = 1;
for (i, ch) in content.char_indices() {
if i >= byte_offset {
break;
}
if ch == '\n' {
line += 1;
col = 1;
} else {
col += 1;
}
}
(line, col)
}
pub fn truncate(s: &str, max: usize) -> String {
if s.len() <= max {
s.to_string()
} else {
let mut end = max.saturating_sub(3);
while !s.is_char_boundary(end) && end > 0 {
end -= 1;
}
format!("{}...", &s[..end])
}
}
pub fn count_non_import_matches(content: &str, target: &str) -> usize {
let mut count = 0;
for line in content.lines() {
let trimmed = line.trim();
if is_comment_line(trimmed) || trimmed.starts_with("use ") {
continue;
}
count += line.matches(target).count();
}
count
}