aboutsummaryrefslogtreecommitdiff
path: root/crates/ide/src/file_structure.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide/src/file_structure.rs')
-rw-r--r--crates/ide/src/file_structure.rs228
1 files changed, 188 insertions, 40 deletions
diff --git a/crates/ide/src/file_structure.rs b/crates/ide/src/file_structure.rs
index 26793bdb4..9f879a66e 100644
--- a/crates/ide/src/file_structure.rs
+++ b/crates/ide/src/file_structure.rs
@@ -1,7 +1,8 @@
1use ide_db::SymbolKind; 1use ide_db::SymbolKind;
2use syntax::{ 2use syntax::{
3 ast::{self, AttrsOwner, GenericParamsOwner, NameOwner}, 3 ast::{self, AttrsOwner, GenericParamsOwner, NameOwner},
4 match_ast, AstNode, SourceFile, SyntaxNode, TextRange, WalkEvent, 4 match_ast, AstNode, AstToken, NodeOrToken, SourceFile, SyntaxNode, SyntaxToken, TextRange,
5 WalkEvent,
5}; 6};
6 7
7#[derive(Debug, Clone)] 8#[derive(Debug, Clone)]
@@ -10,11 +11,17 @@ pub struct StructureNode {
10 pub label: String, 11 pub label: String,
11 pub navigation_range: TextRange, 12 pub navigation_range: TextRange,
12 pub node_range: TextRange, 13 pub node_range: TextRange,
13 pub kind: SymbolKind, 14 pub kind: StructureNodeKind,
14 pub detail: Option<String>, 15 pub detail: Option<String>,
15 pub deprecated: bool, 16 pub deprecated: bool,
16} 17}
17 18
19#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
20pub enum StructureNodeKind {
21 SymbolKind(SymbolKind),
22 Region,
23}
24
18// Feature: File Structure 25// Feature: File Structure
19// 26//
20// Provides a tree of the symbols defined in the file. Can be used to 27// Provides a tree of the symbols defined in the file. Can be used to
@@ -32,34 +39,46 @@ pub(crate) fn file_structure(file: &SourceFile) -> Vec<StructureNode> {
32 let mut res = Vec::new(); 39 let mut res = Vec::new();
33 let mut stack = Vec::new(); 40 let mut stack = Vec::new();
34 41
35 for event in file.syntax().preorder() { 42 for event in file.syntax().preorder_with_tokens() {
36 match event { 43 match event {
37 WalkEvent::Enter(node) => { 44 WalkEvent::Enter(NodeOrToken::Node(node)) => {
38 if let Some(mut symbol) = structure_node(&node) { 45 if let Some(mut symbol) = structure_node(&node) {
39 symbol.parent = stack.last().copied(); 46 symbol.parent = stack.last().copied();
40 stack.push(res.len()); 47 stack.push(res.len());
41 res.push(symbol); 48 res.push(symbol);
42 } 49 }
43 } 50 }
44 WalkEvent::Leave(node) => { 51 WalkEvent::Leave(NodeOrToken::Node(node)) => {
45 if structure_node(&node).is_some() { 52 if structure_node(&node).is_some() {
46 stack.pop().unwrap(); 53 stack.pop().unwrap();
47 } 54 }
48 } 55 }
56 WalkEvent::Enter(NodeOrToken::Token(token)) => {
57 if let Some(mut symbol) = structure_token(token) {
58 symbol.parent = stack.last().copied();
59 stack.push(res.len());
60 res.push(symbol);
61 }
62 }
63 WalkEvent::Leave(NodeOrToken::Token(token)) => {
64 if structure_token(token).is_some() {
65 stack.pop().unwrap();
66 }
67 }
49 } 68 }
50 } 69 }
51 res 70 res
52} 71}
53 72
54fn structure_node(node: &SyntaxNode) -> Option<StructureNode> { 73fn structure_node(node: &SyntaxNode) -> Option<StructureNode> {
55 fn decl<N: NameOwner + AttrsOwner>(node: N, kind: SymbolKind) -> Option<StructureNode> { 74 fn decl<N: NameOwner + AttrsOwner>(node: N, kind: StructureNodeKind) -> Option<StructureNode> {
56 decl_with_detail(&node, None, kind) 75 decl_with_detail(&node, None, kind)
57 } 76 }
58 77
59 fn decl_with_type_ref<N: NameOwner + AttrsOwner>( 78 fn decl_with_type_ref<N: NameOwner + AttrsOwner>(
60 node: &N, 79 node: &N,
61 type_ref: Option<ast::Type>, 80 type_ref: Option<ast::Type>,
62 kind: SymbolKind, 81 kind: StructureNodeKind,
63 ) -> Option<StructureNode> { 82 ) -> Option<StructureNode> {
64 let detail = type_ref.map(|type_ref| { 83 let detail = type_ref.map(|type_ref| {
65 let mut detail = String::new(); 84 let mut detail = String::new();
@@ -72,7 +91,7 @@ fn structure_node(node: &SyntaxNode) -> Option<StructureNode> {
72 fn decl_with_detail<N: NameOwner + AttrsOwner>( 91 fn decl_with_detail<N: NameOwner + AttrsOwner>(
73 node: &N, 92 node: &N,
74 detail: Option<String>, 93 detail: Option<String>,
75 kind: SymbolKind, 94 kind: StructureNodeKind,
76 ) -> Option<StructureNode> { 95 ) -> Option<StructureNode> {
77 let name = node.name()?; 96 let name = node.name()?;
78 97
@@ -120,18 +139,18 @@ fn structure_node(node: &SyntaxNode) -> Option<StructureNode> {
120 collapse_ws(ret_type.syntax(), &mut detail); 139 collapse_ws(ret_type.syntax(), &mut detail);
121 } 140 }
122 141
123 decl_with_detail(&it, Some(detail), SymbolKind::Function) 142 decl_with_detail(&it, Some(detail), StructureNodeKind::SymbolKind(SymbolKind::Function))
124 }, 143 },
125 ast::Struct(it) => decl(it, SymbolKind::Struct), 144 ast::Struct(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Struct)),
126 ast::Union(it) => decl(it, SymbolKind::Union), 145 ast::Union(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Union)),
127 ast::Enum(it) => decl(it, SymbolKind::Enum), 146 ast::Enum(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Enum)),
128 ast::Variant(it) => decl(it, SymbolKind::Variant), 147 ast::Variant(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Variant)),
129 ast::Trait(it) => decl(it, SymbolKind::Trait), 148 ast::Trait(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Trait)),
130 ast::Module(it) => decl(it, SymbolKind::Module), 149 ast::Module(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Module)),
131 ast::TypeAlias(it) => decl_with_type_ref(&it, it.ty(), SymbolKind::TypeAlias), 150 ast::TypeAlias(it) => decl_with_type_ref(&it, it.ty(), StructureNodeKind::SymbolKind(SymbolKind::TypeAlias)),
132 ast::RecordField(it) => decl_with_type_ref(&it, it.ty(), SymbolKind::Field), 151 ast::RecordField(it) => decl_with_type_ref(&it, it.ty(), StructureNodeKind::SymbolKind(SymbolKind::Field)),
133 ast::Const(it) => decl_with_type_ref(&it, it.ty(), SymbolKind::Const), 152 ast::Const(it) => decl_with_type_ref(&it, it.ty(), StructureNodeKind::SymbolKind(SymbolKind::Const)),
134 ast::Static(it) => decl_with_type_ref(&it, it.ty(), SymbolKind::Static), 153 ast::Static(it) => decl_with_type_ref(&it, it.ty(), StructureNodeKind::SymbolKind(SymbolKind::Static)),
135 ast::Impl(it) => { 154 ast::Impl(it) => {
136 let target_type = it.self_ty()?; 155 let target_type = it.self_ty()?;
137 let target_trait = it.trait_(); 156 let target_trait = it.trait_();
@@ -147,18 +166,38 @@ fn structure_node(node: &SyntaxNode) -> Option<StructureNode> {
147 label, 166 label,
148 navigation_range: target_type.syntax().text_range(), 167 navigation_range: target_type.syntax().text_range(),
149 node_range: it.syntax().text_range(), 168 node_range: it.syntax().text_range(),
150 kind: SymbolKind::Impl, 169 kind: StructureNodeKind::SymbolKind(SymbolKind::Impl),
151 detail: None, 170 detail: None,
152 deprecated: false, 171 deprecated: false,
153 }; 172 };
154 Some(node) 173 Some(node)
155 }, 174 },
156 ast::MacroRules(it) => decl(it, SymbolKind::Macro), 175 ast::MacroRules(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Macro)),
157 _ => None, 176 _ => None,
158 } 177 }
159 } 178 }
160} 179}
161 180
181fn structure_token(token: SyntaxToken) -> Option<StructureNode> {
182 if let Some(comment) = ast::Comment::cast(token) {
183 let text = comment.text().trim();
184
185 if let Some(region_name) = text.strip_prefix("// region:").map(str::trim) {
186 return Some(StructureNode {
187 parent: None,
188 label: region_name.to_string(),
189 navigation_range: comment.syntax().text_range(),
190 node_range: comment.syntax().text_range(),
191 kind: StructureNodeKind::Region,
192 detail: None,
193 deprecated: false,
194 });
195 }
196 }
197
198 None
199}
200
162#[cfg(test)] 201#[cfg(test)]
163mod tests { 202mod tests {
164 use expect_test::{expect, Expect}; 203 use expect_test::{expect, Expect};
@@ -217,6 +256,16 @@ fn obsolete() {}
217 256
218#[deprecated(note = "for awhile")] 257#[deprecated(note = "for awhile")]
219fn very_obsolete() {} 258fn very_obsolete() {}
259
260// region: Some region name
261// endregion
262
263// region: dontpanic
264mod m {
265fn f() {}
266// endregion
267fn g() {}
268}
220"#, 269"#,
221 expect![[r#" 270 expect![[r#"
222 [ 271 [
@@ -225,7 +274,9 @@ fn very_obsolete() {}
225 label: "Foo", 274 label: "Foo",
226 navigation_range: 8..11, 275 navigation_range: 8..11,
227 node_range: 1..26, 276 node_range: 1..26,
228 kind: Struct, 277 kind: SymbolKind(
278 Struct,
279 ),
229 detail: None, 280 detail: None,
230 deprecated: false, 281 deprecated: false,
231 }, 282 },
@@ -236,7 +287,9 @@ fn very_obsolete() {}
236 label: "x", 287 label: "x",
237 navigation_range: 18..19, 288 navigation_range: 18..19,
238 node_range: 18..24, 289 node_range: 18..24,
239 kind: Field, 290 kind: SymbolKind(
291 Field,
292 ),
240 detail: Some( 293 detail: Some(
241 "i32", 294 "i32",
242 ), 295 ),
@@ -247,7 +300,9 @@ fn very_obsolete() {}
247 label: "m", 300 label: "m",
248 navigation_range: 32..33, 301 navigation_range: 32..33,
249 node_range: 28..158, 302 node_range: 28..158,
250 kind: Module, 303 kind: SymbolKind(
304 Module,
305 ),
251 detail: None, 306 detail: None,
252 deprecated: false, 307 deprecated: false,
253 }, 308 },
@@ -258,7 +313,9 @@ fn very_obsolete() {}
258 label: "bar1", 313 label: "bar1",
259 navigation_range: 43..47, 314 navigation_range: 43..47,
260 node_range: 40..52, 315 node_range: 40..52,
261 kind: Function, 316 kind: SymbolKind(
317 Function,
318 ),
262 detail: Some( 319 detail: Some(
263 "fn()", 320 "fn()",
264 ), 321 ),
@@ -271,7 +328,9 @@ fn very_obsolete() {}
271 label: "bar2", 328 label: "bar2",
272 navigation_range: 60..64, 329 navigation_range: 60..64,
273 node_range: 57..81, 330 node_range: 57..81,
274 kind: Function, 331 kind: SymbolKind(
332 Function,
333 ),
275 detail: Some( 334 detail: Some(
276 "fn<T>(t: T) -> T", 335 "fn<T>(t: T) -> T",
277 ), 336 ),
@@ -284,7 +343,9 @@ fn very_obsolete() {}
284 label: "bar3", 343 label: "bar3",
285 navigation_range: 89..93, 344 navigation_range: 89..93,
286 node_range: 86..156, 345 node_range: 86..156,
287 kind: Function, 346 kind: SymbolKind(
347 Function,
348 ),
288 detail: Some( 349 detail: Some(
289 "fn<A, B>(a: A, b: B) -> Vec< u32 >", 350 "fn<A, B>(a: A, b: B) -> Vec< u32 >",
290 ), 351 ),
@@ -295,7 +356,9 @@ fn very_obsolete() {}
295 label: "E", 356 label: "E",
296 navigation_range: 165..166, 357 navigation_range: 165..166,
297 node_range: 160..180, 358 node_range: 160..180,
298 kind: Enum, 359 kind: SymbolKind(
360 Enum,
361 ),
299 detail: None, 362 detail: None,
300 deprecated: false, 363 deprecated: false,
301 }, 364 },
@@ -306,7 +369,9 @@ fn very_obsolete() {}
306 label: "X", 369 label: "X",
307 navigation_range: 169..170, 370 navigation_range: 169..170,
308 node_range: 169..170, 371 node_range: 169..170,
309 kind: Variant, 372 kind: SymbolKind(
373 Variant,
374 ),
310 detail: None, 375 detail: None,
311 deprecated: false, 376 deprecated: false,
312 }, 377 },
@@ -317,7 +382,9 @@ fn very_obsolete() {}
317 label: "Y", 382 label: "Y",
318 navigation_range: 172..173, 383 navigation_range: 172..173,
319 node_range: 172..178, 384 node_range: 172..178,
320 kind: Variant, 385 kind: SymbolKind(
386 Variant,
387 ),
321 detail: None, 388 detail: None,
322 deprecated: false, 389 deprecated: false,
323 }, 390 },
@@ -326,7 +393,9 @@ fn very_obsolete() {}
326 label: "T", 393 label: "T",
327 navigation_range: 186..187, 394 navigation_range: 186..187,
328 node_range: 181..193, 395 node_range: 181..193,
329 kind: TypeAlias, 396 kind: SymbolKind(
397 TypeAlias,
398 ),
330 detail: Some( 399 detail: Some(
331 "()", 400 "()",
332 ), 401 ),
@@ -337,7 +406,9 @@ fn very_obsolete() {}
337 label: "S", 406 label: "S",
338 navigation_range: 201..202, 407 navigation_range: 201..202,
339 node_range: 194..213, 408 node_range: 194..213,
340 kind: Static, 409 kind: SymbolKind(
410 Static,
411 ),
341 detail: Some( 412 detail: Some(
342 "i32", 413 "i32",
343 ), 414 ),
@@ -348,7 +419,9 @@ fn very_obsolete() {}
348 label: "C", 419 label: "C",
349 navigation_range: 220..221, 420 navigation_range: 220..221,
350 node_range: 214..232, 421 node_range: 214..232,
351 kind: Const, 422 kind: SymbolKind(
423 Const,
424 ),
352 detail: Some( 425 detail: Some(
353 "i32", 426 "i32",
354 ), 427 ),
@@ -359,7 +432,9 @@ fn very_obsolete() {}
359 label: "impl E", 432 label: "impl E",
360 navigation_range: 239..240, 433 navigation_range: 239..240,
361 node_range: 234..243, 434 node_range: 234..243,
362 kind: Impl, 435 kind: SymbolKind(
436 Impl,
437 ),
363 detail: None, 438 detail: None,
364 deprecated: false, 439 deprecated: false,
365 }, 440 },
@@ -368,7 +443,9 @@ fn very_obsolete() {}
368 label: "impl fmt::Debug for E", 443 label: "impl fmt::Debug for E",
369 navigation_range: 265..266, 444 navigation_range: 265..266,
370 node_range: 245..269, 445 node_range: 245..269,
371 kind: Impl, 446 kind: SymbolKind(
447 Impl,
448 ),
372 detail: None, 449 detail: None,
373 deprecated: false, 450 deprecated: false,
374 }, 451 },
@@ -377,7 +454,9 @@ fn very_obsolete() {}
377 label: "mc", 454 label: "mc",
378 navigation_range: 284..286, 455 navigation_range: 284..286,
379 node_range: 271..303, 456 node_range: 271..303,
380 kind: Macro, 457 kind: SymbolKind(
458 Macro,
459 ),
381 detail: None, 460 detail: None,
382 deprecated: false, 461 deprecated: false,
383 }, 462 },
@@ -386,7 +465,9 @@ fn very_obsolete() {}
386 label: "mcexp", 465 label: "mcexp",
387 navigation_range: 334..339, 466 navigation_range: 334..339,
388 node_range: 305..356, 467 node_range: 305..356,
389 kind: Macro, 468 kind: SymbolKind(
469 Macro,
470 ),
390 detail: None, 471 detail: None,
391 deprecated: false, 472 deprecated: false,
392 }, 473 },
@@ -395,7 +476,9 @@ fn very_obsolete() {}
395 label: "mcexp", 476 label: "mcexp",
396 navigation_range: 387..392, 477 navigation_range: 387..392,
397 node_range: 358..409, 478 node_range: 358..409,
398 kind: Macro, 479 kind: SymbolKind(
480 Macro,
481 ),
399 detail: None, 482 detail: None,
400 deprecated: false, 483 deprecated: false,
401 }, 484 },
@@ -404,7 +487,9 @@ fn very_obsolete() {}
404 label: "obsolete", 487 label: "obsolete",
405 navigation_range: 428..436, 488 navigation_range: 428..436,
406 node_range: 411..441, 489 node_range: 411..441,
407 kind: Function, 490 kind: SymbolKind(
491 Function,
492 ),
408 detail: Some( 493 detail: Some(
409 "fn()", 494 "fn()",
410 ), 495 ),
@@ -415,12 +500,75 @@ fn very_obsolete() {}
415 label: "very_obsolete", 500 label: "very_obsolete",
416 navigation_range: 481..494, 501 navigation_range: 481..494,
417 node_range: 443..499, 502 node_range: 443..499,
418 kind: Function, 503 kind: SymbolKind(
504 Function,
505 ),
419 detail: Some( 506 detail: Some(
420 "fn()", 507 "fn()",
421 ), 508 ),
422 deprecated: true, 509 deprecated: true,
423 }, 510 },
511 StructureNode {
512 parent: None,
513 label: "Some region name",
514 navigation_range: 501..528,
515 node_range: 501..528,
516 kind: Region,
517 detail: None,
518 deprecated: false,
519 },
520 StructureNode {
521 parent: None,
522 label: "m",
523 navigation_range: 568..569,
524 node_range: 543..606,
525 kind: SymbolKind(
526 Module,
527 ),
528 detail: None,
529 deprecated: false,
530 },
531 StructureNode {
532 parent: Some(
533 20,
534 ),
535 label: "dontpanic",
536 navigation_range: 543..563,
537 node_range: 543..563,
538 kind: Region,
539 detail: None,
540 deprecated: false,
541 },
542 StructureNode {
543 parent: Some(
544 20,
545 ),
546 label: "f",
547 navigation_range: 575..576,
548 node_range: 572..581,
549 kind: SymbolKind(
550 Function,
551 ),
552 detail: Some(
553 "fn()",
554 ),
555 deprecated: false,
556 },
557 StructureNode {
558 parent: Some(
559 20,
560 ),
561 label: "g",
562 navigation_range: 598..599,
563 node_range: 582..604,
564 kind: SymbolKind(
565 Function,
566 ),
567 detail: Some(
568 "fn()",
569 ),
570 deprecated: false,
571 },
424 ] 572 ]
425 "#]], 573 "#]],
426 ); 574 );