aboutsummaryrefslogtreecommitdiff
path: root/crates/ide/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide/src')
-rw-r--r--crates/ide/src/folding_ranges.rs55
1 files changed, 47 insertions, 8 deletions
diff --git a/crates/ide/src/folding_ranges.rs b/crates/ide/src/folding_ranges.rs
index 45170dd29..4b1b24562 100644
--- a/crates/ide/src/folding_ranges.rs
+++ b/crates/ide/src/folding_ranges.rs
@@ -6,7 +6,7 @@ use syntax::{
6 ast::{self, AstNode, AstToken, VisibilityOwner}, 6 ast::{self, AstNode, AstToken, VisibilityOwner},
7 Direction, NodeOrToken, SourceFile, 7 Direction, NodeOrToken, SourceFile,
8 SyntaxKind::{self, *}, 8 SyntaxKind::{self, *},
9 SyntaxNode, TextRange, 9 SyntaxNode, TextRange, TextSize,
10}; 10};
11 11
12#[derive(Debug, PartialEq, Eq)] 12#[derive(Debug, PartialEq, Eq)]
@@ -16,6 +16,7 @@ pub enum FoldKind {
16 Mods, 16 Mods,
17 Block, 17 Block,
18 ArgList, 18 ArgList,
19 Region,
19} 20}
20 21
21#[derive(Debug)] 22#[derive(Debug)]
@@ -29,6 +30,8 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
29 let mut visited_comments = FxHashSet::default(); 30 let mut visited_comments = FxHashSet::default();
30 let mut visited_imports = FxHashSet::default(); 31 let mut visited_imports = FxHashSet::default();
31 let mut visited_mods = FxHashSet::default(); 32 let mut visited_mods = FxHashSet::default();
33 // regions can be nested, here is a LIFO buffer
34 let mut regions_starts: Vec<TextSize> = vec![];
32 35
33 for element in file.syntax().descendants_with_tokens() { 36 for element in file.syntax().descendants_with_tokens() {
34 // Fold items that span multiple lines 37 // Fold items that span multiple lines
@@ -48,10 +51,25 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
48 // Fold groups of comments 51 // Fold groups of comments
49 if let Some(comment) = ast::Comment::cast(token) { 52 if let Some(comment) = ast::Comment::cast(token) {
50 if !visited_comments.contains(&comment) { 53 if !visited_comments.contains(&comment) {
51 if let Some(range) = 54 // regions are not real comments
52 contiguous_range_for_comment(comment, &mut visited_comments) 55 if comment.text().trim().starts_with("// region:") {
53 { 56 regions_starts.push(comment.syntax().text_range().start());
54 res.push(Fold { range, kind: FoldKind::Comment }) 57 } else if comment.text().trim().starts_with("// endregion") {
58 if let Some(region) = regions_starts.pop() {
59 res.push(Fold {
60 range: TextRange::new(
61 region,
62 comment.syntax().text_range().end(),
63 ),
64 kind: FoldKind::Region,
65 })
66 }
67 } else {
68 if let Some(range) =
69 contiguous_range_for_comment(comment, &mut visited_comments)
70 {
71 res.push(Fold { range, kind: FoldKind::Comment })
72 }
55 } 73 }
56 } 74 }
57 } 75 }
@@ -175,9 +193,16 @@ fn contiguous_range_for_comment(
175 } 193 }
176 if let Some(c) = ast::Comment::cast(token) { 194 if let Some(c) = ast::Comment::cast(token) {
177 if c.kind() == group_kind { 195 if c.kind() == group_kind {
178 visited.insert(c.clone()); 196 // regions are not real comments
179 last = c; 197 if c.text().trim().starts_with("// region:")
180 continue; 198 || c.text().trim().starts_with("// endregion")
199 {
200 break;
201 } else {
202 visited.insert(c.clone());
203 last = c;
204 continue;
205 }
181 } 206 }
182 } 207 }
183 // The comment group ends because either: 208 // The comment group ends because either:
@@ -224,6 +249,7 @@ mod tests {
224 FoldKind::Mods => "mods", 249 FoldKind::Mods => "mods",
225 FoldKind::Block => "block", 250 FoldKind::Block => "block",
226 FoldKind::ArgList => "arglist", 251 FoldKind::ArgList => "arglist",
252 FoldKind::Region => "region",
227 }; 253 };
228 assert_eq!(kind, &attr.unwrap()); 254 assert_eq!(kind, &attr.unwrap());
229 } 255 }
@@ -418,4 +444,17 @@ fn foo<fold arglist>(
418"#, 444"#,
419 ) 445 )
420 } 446 }
447
448 #[test]
449 fn fold_region() {
450 check(
451 r#"
452// 1. some normal comment
453<fold region>// region: test
454// 2. some normal comment
455calling_function(x,y);
456// endregion: test</fold>
457"#,
458 )
459 }
421} 460}