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