use itertools::{Either, Itertools};
use ra_ap_syntax::ast::{Attr, Item};
use ra_ap_syntax::{AstNode, SyntaxKind, SyntaxNode};
use crate::InkAttribute;
fn ink_attribute_from_node(node: SyntaxNode) -> Option<InkAttribute> {
Attr::cast(node).and_then(InkAttribute::cast)
}
pub fn ink_attrs(node: &SyntaxNode) -> Vec<InkAttribute> {
node.children()
.filter_map(ink_attribute_from_node)
.collect()
}
pub fn ink_attrs_descendants(node: &SyntaxNode) -> Vec<InkAttribute> {
node.children()
.filter(|child| child.kind() != SyntaxKind::ATTR)
.flat_map(|child| {
child
.descendants()
.filter_map(ink_attribute_from_node)
.collect::<Vec<InkAttribute>>()
})
.collect()
}
pub fn ink_attrs_closest_descendants(node: &SyntaxNode) -> Vec<InkAttribute> {
let (ink_children_groups, non_ink_children): (Vec<Vec<InkAttribute>>, Vec<SyntaxNode>) = node
.children()
.filter(|child| child.kind() != SyntaxKind::ATTR)
.partition_map(|child| {
let child_ink_attrs = ink_attrs(&child);
if !child_ink_attrs.is_empty() {
return Either::Left(child_ink_attrs);
}
Either::Right(child)
});
let mut attrs: Vec<InkAttribute> = ink_children_groups.into_iter().flatten().collect();
if !non_ink_children.is_empty() {
attrs.append(
&mut non_ink_children
.iter()
.flat_map(ink_attrs_closest_descendants)
.collect(),
);
}
attrs
}
pub fn ink_attrs_in_scope(node: &SyntaxNode) -> Vec<InkAttribute> {
let mut attrs = ink_attrs(node);
attrs.append(&mut ink_attrs_descendants(node));
attrs
}
pub fn ink_attrs_ancestors(node: &SyntaxNode) -> Vec<InkAttribute> {
let mut attrs = Vec::new();
if let Some(parent) = node.parent() {
attrs = parent
.ancestors()
.flat_map(|ancestor| ink_attrs(&ancestor))
.collect();
}
attrs
}
pub fn ink_attrs_closest_ancestors(node: &SyntaxNode) -> Vec<InkAttribute> {
let mut attrs = Vec::new();
if let Some(parent) = node.parent() {
attrs = ink_attrs(&parent);
if attrs.is_empty() {
attrs = ink_attrs_closest_ancestors(&parent);
}
}
attrs
}
pub fn parent_ast_item(node: &SyntaxNode) -> Option<Item> {
let parent = node.parent()?;
if let Some(item) = Item::cast(parent.clone()) {
Some(item)
} else {
parent_ast_item(&parent)
}
}
#[macro_export]
macro_rules! quote_as_str {
($($tt:tt)*) => {
quote::quote!($($tt)*).to_string().as_str()
};
}