aboutsummaryrefslogtreecommitdiff
path: root/crates/libeditor/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/libeditor/src')
-rw-r--r--crates/libeditor/src/lib.rs2
-rw-r--r--crates/libeditor/src/symbols.rs82
2 files changed, 72 insertions, 12 deletions
diff --git a/crates/libeditor/src/lib.rs b/crates/libeditor/src/lib.rs
index e5933cbd6..b40db2c66 100644
--- a/crates/libeditor/src/lib.rs
+++ b/crates/libeditor/src/lib.rs
@@ -19,7 +19,7 @@ pub use libsyntax2::{File, TextRange, TextUnit};
19pub use self::{ 19pub use self::{
20 line_index::{LineIndex, LineCol}, 20 line_index::{LineIndex, LineCol},
21 extend_selection::extend_selection, 21 extend_selection::extend_selection,
22 symbols::{FileSymbol, file_symbols}, 22 symbols::{StructureNode, file_structure, FileSymbol, file_symbols},
23 edit::{EditBuilder, Edit, AtomEdit}, 23 edit::{EditBuilder, Edit, AtomEdit},
24 code_actions::{flip_comma}, 24 code_actions::{flip_comma},
25}; 25};
diff --git a/crates/libeditor/src/symbols.rs b/crates/libeditor/src/symbols.rs
index f1d5222f4..43f4164da 100644
--- a/crates/libeditor/src/symbols.rs
+++ b/crates/libeditor/src/symbols.rs
@@ -4,22 +4,58 @@ use libsyntax2::{
4 ast::{self, NameOwner}, 4 ast::{self, NameOwner},
5 algo::{ 5 algo::{
6 visit::{visitor, Visitor}, 6 visit::{visitor, Visitor},
7 walk::{walk, WalkEvent}, 7 walk::{walk, WalkEvent, preorder},
8 }, 8 },
9 SyntaxKind::*,
9}; 10};
10use TextRange; 11use TextRange;
11 12
12#[derive(Debug)] 13#[derive(Debug)]
13pub struct FileSymbol { 14pub struct StructureNode {
14 pub parent: Option<usize>, 15 pub parent: Option<usize>,
15 pub name: SmolStr, 16 pub label: String,
16 pub name_range: TextRange, 17 pub navigation_range: TextRange,
17 pub node_range: TextRange, 18 pub node_range: TextRange,
18 pub kind: SyntaxKind, 19 pub kind: SyntaxKind,
19} 20}
20 21
22#[derive(Debug)]
23pub struct FileSymbol {
24 pub name: SmolStr,
25 pub node_range: TextRange,
26 pub kind: SyntaxKind,
27}
21 28
22pub fn file_symbols(file: &ast::File) -> Vec<FileSymbol> { 29pub fn file_symbols(file: &ast::File) -> Vec<FileSymbol> {
30 let syntax = file.syntax();
31 preorder(syntax.as_ref())
32 .filter_map(to_symbol)
33 .collect()
34}
35
36fn to_symbol(node: SyntaxNodeRef) -> Option<FileSymbol> {
37 fn decl<'a, N: NameOwner<&'a SyntaxRoot>>(node: N) -> Option<FileSymbol> {
38 let name = node.name()?;
39 Some(FileSymbol {
40 name: name.text(),
41 node_range: node.syntax().range(),
42 kind: node.syntax().kind(),
43 })
44 }
45 visitor()
46 .visit(decl::<ast::FnDef<_>>)
47 .visit(decl::<ast::StructDef<_>>)
48 .visit(decl::<ast::EnumDef<_>>)
49 .visit(decl::<ast::TraitDef<_>>)
50 .visit(decl::<ast::Module<_>>)
51 .visit(decl::<ast::TypeDef<_>>)
52 .visit(decl::<ast::ConstDef<_>>)
53 .visit(decl::<ast::StaticDef<_>>)
54 .accept(node)?
55}
56
57
58pub fn file_structure(file: &ast::File) -> Vec<StructureNode> {
23 let mut res = Vec::new(); 59 let mut res = Vec::new();
24 let mut stack = Vec::new(); 60 let mut stack = Vec::new();
25 let syntax = file.syntax(); 61 let syntax = file.syntax();
@@ -27,7 +63,7 @@ pub fn file_symbols(file: &ast::File) -> Vec<FileSymbol> {
27 for event in walk(syntax.as_ref()) { 63 for event in walk(syntax.as_ref()) {
28 match event { 64 match event {
29 WalkEvent::Enter(node) => { 65 WalkEvent::Enter(node) => {
30 match to_symbol(node) { 66 match structure_node(node) {
31 Some(mut symbol) => { 67 Some(mut symbol) => {
32 symbol.parent = stack.last().map(|&n| n); 68 symbol.parent = stack.last().map(|&n| n);
33 stack.push(res.len()); 69 stack.push(res.len());
@@ -37,7 +73,7 @@ pub fn file_symbols(file: &ast::File) -> Vec<FileSymbol> {
37 } 73 }
38 } 74 }
39 WalkEvent::Exit(node) => { 75 WalkEvent::Exit(node) => {
40 if to_symbol(node).is_some() { 76 if structure_node(node).is_some() {
41 stack.pop().unwrap(); 77 stack.pop().unwrap();
42 } 78 }
43 } 79 }
@@ -46,13 +82,13 @@ pub fn file_symbols(file: &ast::File) -> Vec<FileSymbol> {
46 res 82 res
47} 83}
48 84
49fn to_symbol(node: SyntaxNodeRef) -> Option<FileSymbol> { 85fn structure_node(node: SyntaxNodeRef) -> Option<StructureNode> {
50 fn decl<'a, N: NameOwner<&'a SyntaxRoot>>(node: N) -> Option<FileSymbol> { 86 fn decl<'a, N: NameOwner<&'a SyntaxRoot>>(node: N) -> Option<StructureNode> {
51 let name = node.name()?; 87 let name = node.name()?;
52 Some(FileSymbol { 88 Some(StructureNode {
53 parent: None, 89 parent: None,
54 name: name.text(), 90 label: name.text().to_string(),
55 name_range: name.syntax().range(), 91 navigation_range: name.syntax().range(),
56 node_range: node.syntax().range(), 92 node_range: node.syntax().range(),
57 kind: node.syntax().kind(), 93 kind: node.syntax().kind(),
58 }) 94 })
@@ -67,5 +103,29 @@ fn to_symbol(node: SyntaxNodeRef) -> Option<FileSymbol> {
67 .visit(decl::<ast::TypeDef<_>>) 103 .visit(decl::<ast::TypeDef<_>>)
68 .visit(decl::<ast::ConstDef<_>>) 104 .visit(decl::<ast::ConstDef<_>>)
69 .visit(decl::<ast::StaticDef<_>>) 105 .visit(decl::<ast::StaticDef<_>>)
106 .visit(|im: ast::ImplItem<_>| {
107 let mut label = String::new();
108 let brace = im.syntax().children()
109 .find(|it| {
110 let stop = it.kind() == L_CURLY;
111 if !stop {
112 label.push_str(&it.text());
113 }
114 stop
115 })?;
116 let navigation_range = TextRange::from_to(
117 im.syntax().range().start(),
118 brace.range().start(),
119 );
120
121 let node = StructureNode {
122 parent: None,
123 label,
124 navigation_range,
125 node_range: im.syntax().range(),
126 kind: im.syntax().kind(),
127 };
128 Some(node)
129 })
70 .accept(node)? 130 .accept(node)?
71} 131}