2018-08-11 11:28:59 +02:00
|
|
|
use libsyntax2::{
|
2018-08-25 10:44:58 +02:00
|
|
|
SyntaxKind, SyntaxNodeRef, AstNode, File, SmolStr,
|
2018-08-11 11:28:59 +02:00
|
|
|
ast::{self, NameOwner},
|
|
|
|
algo::{
|
|
|
|
visit::{visitor, Visitor},
|
2018-08-14 10:20:09 +02:00
|
|
|
walk::{walk, WalkEvent, preorder},
|
2018-08-11 11:28:59 +02:00
|
|
|
},
|
|
|
|
};
|
|
|
|
use TextRange;
|
|
|
|
|
2018-08-17 14:37:17 +02:00
|
|
|
#[derive(Debug, Clone)]
|
2018-08-14 10:20:09 +02:00
|
|
|
pub struct StructureNode {
|
2018-08-11 11:28:59 +02:00
|
|
|
pub parent: Option<usize>,
|
2018-08-14 10:20:09 +02:00
|
|
|
pub label: String,
|
|
|
|
pub navigation_range: TextRange,
|
2018-08-11 11:28:59 +02:00
|
|
|
pub node_range: TextRange,
|
|
|
|
pub kind: SyntaxKind,
|
|
|
|
}
|
|
|
|
|
2018-08-17 14:37:17 +02:00
|
|
|
#[derive(Debug, Clone)]
|
2018-08-14 10:20:09 +02:00
|
|
|
pub struct FileSymbol {
|
|
|
|
pub name: SmolStr,
|
|
|
|
pub node_range: TextRange,
|
|
|
|
pub kind: SyntaxKind,
|
|
|
|
}
|
2018-08-11 11:28:59 +02:00
|
|
|
|
2018-08-25 10:44:58 +02:00
|
|
|
pub fn file_symbols(file: &File) -> Vec<FileSymbol> {
|
2018-08-17 21:00:13 +02:00
|
|
|
preorder(file.syntax())
|
2018-08-14 10:20:09 +02:00
|
|
|
.filter_map(to_symbol)
|
|
|
|
.collect()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn to_symbol(node: SyntaxNodeRef) -> Option<FileSymbol> {
|
2018-08-17 21:00:13 +02:00
|
|
|
fn decl<'a, N: NameOwner<'a>>(node: N) -> Option<FileSymbol> {
|
2018-08-14 10:20:09 +02:00
|
|
|
let name = node.name()?;
|
|
|
|
Some(FileSymbol {
|
|
|
|
name: name.text(),
|
|
|
|
node_range: node.syntax().range(),
|
|
|
|
kind: node.syntax().kind(),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
visitor()
|
2018-08-17 21:00:13 +02:00
|
|
|
.visit(decl::<ast::FnDef>)
|
|
|
|
.visit(decl::<ast::StructDef>)
|
|
|
|
.visit(decl::<ast::EnumDef>)
|
|
|
|
.visit(decl::<ast::TraitDef>)
|
|
|
|
.visit(decl::<ast::Module>)
|
|
|
|
.visit(decl::<ast::TypeDef>)
|
|
|
|
.visit(decl::<ast::ConstDef>)
|
|
|
|
.visit(decl::<ast::StaticDef>)
|
2018-08-14 10:20:09 +02:00
|
|
|
.accept(node)?
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-08-25 10:44:58 +02:00
|
|
|
pub fn file_structure(file: &File) -> Vec<StructureNode> {
|
2018-08-11 11:28:59 +02:00
|
|
|
let mut res = Vec::new();
|
|
|
|
let mut stack = Vec::new();
|
|
|
|
|
2018-08-17 21:00:13 +02:00
|
|
|
for event in walk(file.syntax()) {
|
2018-08-11 11:28:59 +02:00
|
|
|
match event {
|
|
|
|
WalkEvent::Enter(node) => {
|
2018-08-14 10:20:09 +02:00
|
|
|
match structure_node(node) {
|
2018-08-11 11:28:59 +02:00
|
|
|
Some(mut symbol) => {
|
|
|
|
symbol.parent = stack.last().map(|&n| n);
|
|
|
|
stack.push(res.len());
|
|
|
|
res.push(symbol);
|
|
|
|
}
|
|
|
|
None => (),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
WalkEvent::Exit(node) => {
|
2018-08-14 10:20:09 +02:00
|
|
|
if structure_node(node).is_some() {
|
2018-08-11 11:28:59 +02:00
|
|
|
stack.pop().unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
res
|
|
|
|
}
|
|
|
|
|
2018-08-14 10:20:09 +02:00
|
|
|
fn structure_node(node: SyntaxNodeRef) -> Option<StructureNode> {
|
2018-08-17 21:00:13 +02:00
|
|
|
fn decl<'a, N: NameOwner<'a>>(node: N) -> Option<StructureNode> {
|
2018-08-11 11:28:59 +02:00
|
|
|
let name = node.name()?;
|
2018-08-14 10:20:09 +02:00
|
|
|
Some(StructureNode {
|
2018-08-11 11:28:59 +02:00
|
|
|
parent: None,
|
2018-08-14 10:20:09 +02:00
|
|
|
label: name.text().to_string(),
|
|
|
|
navigation_range: name.syntax().range(),
|
2018-08-11 11:28:59 +02:00
|
|
|
node_range: node.syntax().range(),
|
|
|
|
kind: node.syntax().kind(),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
visitor()
|
2018-08-17 21:00:13 +02:00
|
|
|
.visit(decl::<ast::FnDef>)
|
|
|
|
.visit(decl::<ast::StructDef>)
|
2018-08-24 18:27:30 +02:00
|
|
|
.visit(decl::<ast::NamedFieldDef>)
|
2018-08-17 21:00:13 +02:00
|
|
|
.visit(decl::<ast::EnumDef>)
|
|
|
|
.visit(decl::<ast::TraitDef>)
|
|
|
|
.visit(decl::<ast::Module>)
|
|
|
|
.visit(decl::<ast::TypeDef>)
|
|
|
|
.visit(decl::<ast::ConstDef>)
|
|
|
|
.visit(decl::<ast::StaticDef>)
|
|
|
|
.visit(|im: ast::ImplItem| {
|
2018-08-14 11:38:20 +02:00
|
|
|
let target_type = im.target_type()?;
|
|
|
|
let target_trait = im.target_trait();
|
|
|
|
let label = match target_trait {
|
|
|
|
None => format!("impl {}", target_type.syntax().text()),
|
|
|
|
Some(t) => format!(
|
|
|
|
"impl {} for {}",
|
|
|
|
t.syntax().text(),
|
|
|
|
target_type.syntax().text(),
|
|
|
|
),
|
|
|
|
};
|
2018-08-14 10:20:09 +02:00
|
|
|
|
|
|
|
let node = StructureNode {
|
|
|
|
parent: None,
|
|
|
|
label,
|
2018-08-14 11:38:20 +02:00
|
|
|
navigation_range: target_type.syntax().range(),
|
2018-08-14 10:20:09 +02:00
|
|
|
node_range: im.syntax().range(),
|
|
|
|
kind: im.syntax().kind(),
|
|
|
|
};
|
|
|
|
Some(node)
|
|
|
|
})
|
2018-08-11 11:28:59 +02:00
|
|
|
.accept(node)?
|
|
|
|
}
|