use ra_ap_syntax::{NodeOrToken, SyntaxKind, SyntaxNode, SyntaxToken};
pub fn collect_preceding_comments_in_list(
children: &[NodeOrToken<SyntaxNode, SyntaxToken>],
item_idx: usize,
) -> Vec<String> {
let mut comments = Vec::new();
for i in (0..item_idx).rev() {
match &children[i] {
NodeOrToken::Token(t) => {
if t.kind() == SyntaxKind::COMMENT {
let text = t.text().to_string();
if !text.starts_with("///") && !text.starts_with("//!") {
comments.push(text);
}
} else if t.kind() == SyntaxKind::WHITESPACE {
if t.text().matches('\n').count() >= 2 {
break;
}
} else {
break;
}
}
NodeOrToken::Node(_) => break,
}
}
comments.reverse();
comments
}
pub fn should_have_blank_line_before_comment(
children: &[NodeOrToken<SyntaxNode, SyntaxToken>],
comment_idx: usize,
) -> bool {
for i in (0..comment_idx).rev() {
match &children[i] {
NodeOrToken::Token(t) => {
if t.kind() == SyntaxKind::WHITESPACE {
if t.text().matches('\n').count() >= 2 {
return true;
}
} else if t.kind() == SyntaxKind::COMMENT {
continue;
} else {
return false;
}
}
NodeOrToken::Node(_) => return false,
}
}
false
}
pub fn is_comment_attached_to_next_item(
children: &[NodeOrToken<SyntaxNode, SyntaxToken>],
comment_idx: usize,
item_kinds: &[SyntaxKind],
) -> bool {
for child_item in children.iter().skip(comment_idx + 1) {
match &child_item {
NodeOrToken::Token(t) => {
if t.kind() == SyntaxKind::WHITESPACE {
if t.text().matches('\n').count() >= 2 {
return false;
}
} else if t.kind() != SyntaxKind::COMMENT {
return false;
}
}
NodeOrToken::Node(n) => {
return item_kinds.contains(&n.kind());
}
}
}
false
}
pub fn get_trailing_comment_sibling(node: &SyntaxNode) -> Option<(String, String)> {
let mut next = node.next_sibling_or_token();
let mut whitespace_before = String::new();
while let Some(item) = next {
match &item {
NodeOrToken::Token(t) => {
if t.kind() == SyntaxKind::COMMENT {
return Some((whitespace_before, t.text().to_string()));
} else if t.kind() == SyntaxKind::WHITESPACE {
if t.text().contains('\n') {
return None;
}
whitespace_before = t.text().to_string();
} else if t.kind() == SyntaxKind::COMMA || t.kind() == SyntaxKind::SEMICOLON {
whitespace_before.clear();
} else {
return None;
}
next = t.next_sibling_or_token();
}
NodeOrToken::Node(_) => return None,
}
}
None
}
pub fn has_newline_before_node(node: &SyntaxNode) -> bool {
let mut current = node.prev_sibling_or_token();
while let Some(item) = current {
match &item {
NodeOrToken::Token(t) => {
if t.kind() == SyntaxKind::WHITESPACE {
return t.text().contains('\n');
} else if t.kind() == SyntaxKind::COMMA || t.kind() == SyntaxKind::SEMICOLON {
current = t.prev_sibling_or_token();
continue;
} else {
return false;
}
}
NodeOrToken::Node(_) => return false,
}
}
false
}