aboutsummaryrefslogtreecommitdiff
path: root/crates/libeditor/src/symbols.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/libeditor/src/symbols.rs')
-rw-r--r--crates/libeditor/src/symbols.rs167
1 files changed, 0 insertions, 167 deletions
diff --git a/crates/libeditor/src/symbols.rs b/crates/libeditor/src/symbols.rs
deleted file mode 100644
index 2f9cc9233..000000000
--- a/crates/libeditor/src/symbols.rs
+++ /dev/null
@@ -1,167 +0,0 @@
1use libsyntax2::{
2 SyntaxKind, SyntaxNodeRef, AstNode, File, SmolStr,
3 ast::{self, NameOwner},
4 algo::{
5 visit::{visitor, Visitor},
6 walk::{walk, WalkEvent, preorder},
7 },
8};
9use TextRange;
10
11#[derive(Debug, Clone)]
12pub struct StructureNode {
13 pub parent: Option<usize>,
14 pub label: String,
15 pub navigation_range: TextRange,
16 pub node_range: TextRange,
17 pub kind: SyntaxKind,
18}
19
20#[derive(Debug, Clone, Hash)]
21pub struct FileSymbol {
22 pub name: SmolStr,
23 pub node_range: TextRange,
24 pub kind: SyntaxKind,
25}
26
27pub fn file_symbols(file: &File) -> Vec<FileSymbol> {
28 preorder(file.syntax())
29 .filter_map(to_symbol)
30 .collect()
31}
32
33fn to_symbol(node: SyntaxNodeRef) -> Option<FileSymbol> {
34 fn decl<'a, N: NameOwner<'a>>(node: N) -> Option<FileSymbol> {
35 let name = node.name()?;
36 Some(FileSymbol {
37 name: name.text(),
38 node_range: node.syntax().range(),
39 kind: node.syntax().kind(),
40 })
41 }
42 visitor()
43 .visit(decl::<ast::FnDef>)
44 .visit(decl::<ast::StructDef>)
45 .visit(decl::<ast::EnumDef>)
46 .visit(decl::<ast::TraitDef>)
47 .visit(decl::<ast::Module>)
48 .visit(decl::<ast::TypeDef>)
49 .visit(decl::<ast::ConstDef>)
50 .visit(decl::<ast::StaticDef>)
51 .accept(node)?
52}
53
54
55pub fn file_structure(file: &File) -> Vec<StructureNode> {
56 let mut res = Vec::new();
57 let mut stack = Vec::new();
58
59 for event in walk(file.syntax()) {
60 match event {
61 WalkEvent::Enter(node) => {
62 match structure_node(node) {
63 Some(mut symbol) => {
64 symbol.parent = stack.last().map(|&n| n);
65 stack.push(res.len());
66 res.push(symbol);
67 }
68 None => (),
69 }
70 }
71 WalkEvent::Exit(node) => {
72 if structure_node(node).is_some() {
73 stack.pop().unwrap();
74 }
75 }
76 }
77 }
78 res
79}
80
81fn structure_node(node: SyntaxNodeRef) -> Option<StructureNode> {
82 fn decl<'a, N: NameOwner<'a>>(node: N) -> Option<StructureNode> {
83 let name = node.name()?;
84 Some(StructureNode {
85 parent: None,
86 label: name.text().to_string(),
87 navigation_range: name.syntax().range(),
88 node_range: node.syntax().range(),
89 kind: node.syntax().kind(),
90 })
91 }
92
93 visitor()
94 .visit(decl::<ast::FnDef>)
95 .visit(decl::<ast::StructDef>)
96 .visit(decl::<ast::NamedFieldDef>)
97 .visit(decl::<ast::EnumDef>)
98 .visit(decl::<ast::TraitDef>)
99 .visit(decl::<ast::Module>)
100 .visit(decl::<ast::TypeDef>)
101 .visit(decl::<ast::ConstDef>)
102 .visit(decl::<ast::StaticDef>)
103 .visit(|im: ast::ImplItem| {
104 let target_type = im.target_type()?;
105 let target_trait = im.target_trait();
106 let label = match target_trait {
107 None => format!("impl {}", target_type.syntax().text()),
108 Some(t) => format!(
109 "impl {} for {}",
110 t.syntax().text(),
111 target_type.syntax().text(),
112 ),
113 };
114
115 let node = StructureNode {
116 parent: None,
117 label,
118 navigation_range: target_type.syntax().range(),
119 node_range: im.syntax().range(),
120 kind: im.syntax().kind(),
121 };
122 Some(node)
123 })
124 .accept(node)?
125}
126
127#[cfg(test)]
128mod tests {
129 use super::*;
130 use test_utils::assert_eq_dbg;
131
132 #[test]
133 fn test_file_structure() {
134 let file = File::parse(r#"
135struct Foo {
136 x: i32
137}
138
139mod m {
140 fn bar() {}
141}
142
143enum E { X, Y(i32) }
144type T = ();
145static S: i32 = 92;
146const C: i32 = 92;
147
148impl E {}
149
150impl fmt::Debug for E {}
151"#);
152 let symbols = file_structure(&file);
153 assert_eq_dbg(
154 r#"[StructureNode { parent: None, label: "Foo", navigation_range: [8; 11), node_range: [1; 26), kind: STRUCT_DEF },
155 StructureNode { parent: Some(0), label: "x", navigation_range: [18; 19), node_range: [18; 24), kind: NAMED_FIELD_DEF },
156 StructureNode { parent: None, label: "m", navigation_range: [32; 33), node_range: [28; 53), kind: MODULE },
157 StructureNode { parent: Some(2), label: "bar", navigation_range: [43; 46), node_range: [40; 51), kind: FN_DEF },
158 StructureNode { parent: None, label: "E", navigation_range: [60; 61), node_range: [55; 75), kind: ENUM_DEF },
159 StructureNode { parent: None, label: "T", navigation_range: [81; 82), node_range: [76; 88), kind: TYPE_DEF },
160 StructureNode { parent: None, label: "S", navigation_range: [96; 97), node_range: [89; 108), kind: STATIC_DEF },
161 StructureNode { parent: None, label: "C", navigation_range: [115; 116), node_range: [109; 127), kind: CONST_DEF },
162 StructureNode { parent: None, label: "impl E", navigation_range: [134; 135), node_range: [129; 138), kind: IMPL_ITEM },
163 StructureNode { parent: None, label: "impl fmt::Debug for E", navigation_range: [160; 161), node_range: [140; 164), kind: IMPL_ITEM }]"#,
164 &symbols,
165 )
166 }
167}