diff options
Diffstat (limited to 'crates/ra_ide_api_light')
-rw-r--r-- | crates/ra_ide_api_light/src/folding_ranges.rs | 64 |
1 files changed, 63 insertions, 1 deletions
diff --git a/crates/ra_ide_api_light/src/folding_ranges.rs b/crates/ra_ide_api_light/src/folding_ranges.rs index 288bba0ce..87feb9bd8 100644 --- a/crates/ra_ide_api_light/src/folding_ranges.rs +++ b/crates/ra_ide_api_light/src/folding_ranges.rs | |||
@@ -9,6 +9,7 @@ use ra_syntax::{ | |||
9 | pub enum FoldKind { | 9 | pub enum FoldKind { |
10 | Comment, | 10 | Comment, |
11 | Imports, | 11 | Imports, |
12 | Mods, | ||
12 | Block, | 13 | Block, |
13 | } | 14 | } |
14 | 15 | ||
@@ -22,6 +23,7 @@ pub fn folding_ranges(file: &SourceFile) -> Vec<Fold> { | |||
22 | let mut res = vec![]; | 23 | let mut res = vec![]; |
23 | let mut visited_comments = FxHashSet::default(); | 24 | let mut visited_comments = FxHashSet::default(); |
24 | let mut visited_imports = FxHashSet::default(); | 25 | let mut visited_imports = FxHashSet::default(); |
26 | let mut visited_mods = FxHashSet::default(); | ||
25 | 27 | ||
26 | for node in file.syntax().descendants() { | 28 | for node in file.syntax().descendants() { |
27 | // Fold items that span multiple lines | 29 | // Fold items that span multiple lines |
@@ -53,6 +55,18 @@ pub fn folding_ranges(file: &SourceFile) -> Vec<Fold> { | |||
53 | }) | 55 | }) |
54 | } | 56 | } |
55 | } | 57 | } |
58 | |||
59 | // Fold groups of mods | ||
60 | if node.kind() == MODULE && !has_visibility(&node) && !visited_mods.contains(&node) { | ||
61 | if let Some(range) = | ||
62 | contiguous_range_for_group_unless(node, has_visibility, &mut visited_mods) | ||
63 | { | ||
64 | res.push(Fold { | ||
65 | range, | ||
66 | kind: FoldKind::Mods, | ||
67 | }) | ||
68 | } | ||
69 | } | ||
56 | } | 70 | } |
57 | 71 | ||
58 | res | 72 | res |
@@ -68,6 +82,14 @@ fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> { | |||
68 | } | 82 | } |
69 | } | 83 | } |
70 | 84 | ||
85 | fn has_visibility(node: &SyntaxNode) -> bool { | ||
86 | use ast::VisibilityOwner; | ||
87 | |||
88 | return ast::Module::cast(node) | ||
89 | .and_then(|m| m.visibility()) | ||
90 | .is_some(); | ||
91 | } | ||
92 | |||
71 | fn has_newline(node: &SyntaxNode) -> bool { | 93 | fn has_newline(node: &SyntaxNode) -> bool { |
72 | for descendant in node.descendants() { | 94 | for descendant in node.descendants() { |
73 | if let Some(ws) = ast::Whitespace::cast(descendant) { | 95 | if let Some(ws) = ast::Whitespace::cast(descendant) { |
@@ -88,6 +110,14 @@ fn contiguous_range_for_group<'a>( | |||
88 | first: &'a SyntaxNode, | 110 | first: &'a SyntaxNode, |
89 | visited: &mut FxHashSet<&'a SyntaxNode>, | 111 | visited: &mut FxHashSet<&'a SyntaxNode>, |
90 | ) -> Option<TextRange> { | 112 | ) -> Option<TextRange> { |
113 | contiguous_range_for_group_unless(first, |_| false, visited) | ||
114 | } | ||
115 | |||
116 | fn contiguous_range_for_group_unless<'a>( | ||
117 | first: &'a SyntaxNode, | ||
118 | unless: impl Fn(&'a SyntaxNode) -> bool, | ||
119 | visited: &mut FxHashSet<&'a SyntaxNode>, | ||
120 | ) -> Option<TextRange> { | ||
91 | visited.insert(first); | 121 | visited.insert(first); |
92 | 122 | ||
93 | let mut last = first; | 123 | let mut last = first; |
@@ -103,7 +133,7 @@ fn contiguous_range_for_group<'a>( | |||
103 | } | 133 | } |
104 | 134 | ||
105 | // Stop if we find a node that doesn't belong to the group | 135 | // Stop if we find a node that doesn't belong to the group |
106 | if node.kind() != first.kind() { | 136 | if node.kind() != first.kind() || unless(node) { |
107 | break; | 137 | break; |
108 | } | 138 | } |
109 | 139 | ||
@@ -245,6 +275,38 @@ fn main() <fold>{ | |||
245 | } | 275 | } |
246 | 276 | ||
247 | #[test] | 277 | #[test] |
278 | fn test_fold_mods() { | ||
279 | let text = r#" | ||
280 | |||
281 | pub mod foo; | ||
282 | <fold>mod after_pub; | ||
283 | mod after_pub_next;</fold> | ||
284 | |||
285 | <fold>mod before_pub; | ||
286 | mod before_pub_next;</fold> | ||
287 | pub mod bar; | ||
288 | |||
289 | mod not_folding_single; | ||
290 | pub mod foobar; | ||
291 | pub not_folding_single_next; | ||
292 | |||
293 | <fold>#[cfg(test)] | ||
294 | mod with_attribute; | ||
295 | mod with_attribute_next;</fold> | ||
296 | |||
297 | fn main() <fold>{ | ||
298 | }</fold>"#; | ||
299 | |||
300 | let folds = &[ | ||
301 | FoldKind::Mods, | ||
302 | FoldKind::Mods, | ||
303 | FoldKind::Mods, | ||
304 | FoldKind::Block, | ||
305 | ]; | ||
306 | do_check(text, folds); | ||
307 | } | ||
308 | |||
309 | #[test] | ||
248 | fn test_fold_import_groups() { | 310 | fn test_fold_import_groups() { |
249 | let text = r#" | 311 | let text = r#" |
250 | <fold>use std::str; | 312 | <fold>use std::str; |