diff options
author | Aleksey Kladov <[email protected]> | 2018-08-11 10:28:59 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2018-08-11 10:28:59 +0100 |
commit | 7afd84febc76a75a3ed1be75c57ff35d7b8b3de6 (patch) | |
tree | 76eb2de7efc569c39cc721b7be298490b9647e0b /crates/libeditor/src/symbols.rs | |
parent | d5119133fc03694c6644cac9e307d1d496fc9bf2 (diff) |
visitor
Diffstat (limited to 'crates/libeditor/src/symbols.rs')
-rw-r--r-- | crates/libeditor/src/symbols.rs | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/crates/libeditor/src/symbols.rs b/crates/libeditor/src/symbols.rs new file mode 100644 index 000000000..3faf96868 --- /dev/null +++ b/crates/libeditor/src/symbols.rs | |||
@@ -0,0 +1,67 @@ | |||
1 | use libsyntax2::{ | ||
2 | SyntaxKind, SyntaxNodeRef, SyntaxRoot, AstNode, | ||
3 | ast::{self, NameOwner}, | ||
4 | algo::{ | ||
5 | visit::{visitor, Visitor}, | ||
6 | walk::{walk, WalkEvent}, | ||
7 | }, | ||
8 | }; | ||
9 | use TextRange; | ||
10 | |||
11 | #[derive(Debug)] | ||
12 | pub struct FileSymbol { | ||
13 | pub parent: Option<usize>, | ||
14 | pub name: String, | ||
15 | pub name_range: TextRange, | ||
16 | pub node_range: TextRange, | ||
17 | pub kind: SyntaxKind, | ||
18 | } | ||
19 | |||
20 | |||
21 | pub fn file_symbols(file: &ast::File) -> Vec<FileSymbol> { | ||
22 | let mut res = Vec::new(); | ||
23 | let mut stack = Vec::new(); | ||
24 | let syntax = file.syntax(); | ||
25 | |||
26 | for event in walk(syntax.as_ref()) { | ||
27 | match event { | ||
28 | WalkEvent::Enter(node) => { | ||
29 | match to_symbol(node) { | ||
30 | Some(mut symbol) => { | ||
31 | symbol.parent = stack.last().map(|&n| n); | ||
32 | stack.push(res.len()); | ||
33 | res.push(symbol); | ||
34 | } | ||
35 | None => (), | ||
36 | } | ||
37 | } | ||
38 | WalkEvent::Exit(node) => { | ||
39 | if to_symbol(node).is_some() { | ||
40 | stack.pop().unwrap(); | ||
41 | } | ||
42 | } | ||
43 | } | ||
44 | } | ||
45 | res | ||
46 | } | ||
47 | |||
48 | fn to_symbol(node: SyntaxNodeRef) -> Option<FileSymbol> { | ||
49 | fn decl<'a, N: NameOwner<&'a SyntaxRoot>>(node: N) -> Option<FileSymbol> { | ||
50 | let name = node.name()?; | ||
51 | Some(FileSymbol { | ||
52 | parent: None, | ||
53 | name: name.text(), | ||
54 | name_range: name.syntax().range(), | ||
55 | node_range: node.syntax().range(), | ||
56 | kind: node.syntax().kind(), | ||
57 | }) | ||
58 | } | ||
59 | |||
60 | visitor() | ||
61 | .visit(decl::<ast::Function<_>>) | ||
62 | .visit(decl::<ast::Struct<_>>) | ||
63 | .visit(decl::<ast::Enum<_>>) | ||
64 | .visit(decl::<ast::Trait<_>>) | ||
65 | .visit(decl::<ast::Module<_>>) | ||
66 | .accept(node)? | ||
67 | } | ||