use libsyntax2::{ SyntaxKind, SyntaxNodeRef, SyntaxRoot, AstNode, ast::{self, NameOwner}, algo::{ visit::{visitor, Visitor}, walk::{walk, WalkEvent}, }, }; use TextRange; #[derive(Debug)] pub struct FileSymbol { pub parent: Option, pub name: String, pub name_range: TextRange, pub node_range: TextRange, pub kind: SyntaxKind, } pub fn file_symbols(file: &ast::File) -> Vec { let mut res = Vec::new(); let mut stack = Vec::new(); let syntax = file.syntax(); for event in walk(syntax.as_ref()) { match event { WalkEvent::Enter(node) => { match to_symbol(node) { Some(mut symbol) => { symbol.parent = stack.last().map(|&n| n); stack.push(res.len()); res.push(symbol); } None => (), } } WalkEvent::Exit(node) => { if to_symbol(node).is_some() { stack.pop().unwrap(); } } } } res } fn to_symbol(node: SyntaxNodeRef) -> Option { fn decl<'a, N: NameOwner<&'a SyntaxRoot>>(node: N) -> Option { let name = node.name()?; Some(FileSymbol { parent: None, name: name.text(), name_range: name.syntax().range(), node_range: node.syntax().range(), kind: node.syntax().kind(), }) } visitor() .visit(decl::>) .visit(decl::>) .visit(decl::>) .visit(decl::>) .visit(decl::>) .visit(decl::>) .visit(decl::>) .visit(decl::>) .accept(node)? }