diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_ide_api_light/src/folding_ranges.rs | 60 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main_loop/handlers.rs | 1 |
2 files changed, 60 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..0f2f1399b 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,10 @@ fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> { | |||
68 | } | 82 | } |
69 | } | 83 | } |
70 | 84 | ||
85 | fn has_visibility(node: &SyntaxNode) -> bool { | ||
86 | return node.descendants().any(|n| n.kind() == VISIBILITY); | ||
87 | } | ||
88 | |||
71 | fn has_newline(node: &SyntaxNode) -> bool { | 89 | fn has_newline(node: &SyntaxNode) -> bool { |
72 | for descendant in node.descendants() { | 90 | for descendant in node.descendants() { |
73 | if let Some(ws) = ast::Whitespace::cast(descendant) { | 91 | if let Some(ws) = ast::Whitespace::cast(descendant) { |
@@ -88,6 +106,14 @@ fn contiguous_range_for_group<'a>( | |||
88 | first: &'a SyntaxNode, | 106 | first: &'a SyntaxNode, |
89 | visited: &mut FxHashSet<&'a SyntaxNode>, | 107 | visited: &mut FxHashSet<&'a SyntaxNode>, |
90 | ) -> Option<TextRange> { | 108 | ) -> Option<TextRange> { |
109 | contiguous_range_for_group_unless(first, |_| false, visited) | ||
110 | } | ||
111 | |||
112 | fn contiguous_range_for_group_unless<'a>( | ||
113 | first: &'a SyntaxNode, | ||
114 | unless: impl Fn(&'a SyntaxNode) -> bool, | ||
115 | visited: &mut FxHashSet<&'a SyntaxNode>, | ||
116 | ) -> Option<TextRange> { | ||
91 | visited.insert(first); | 117 | visited.insert(first); |
92 | 118 | ||
93 | let mut last = first; | 119 | let mut last = first; |
@@ -103,7 +129,7 @@ fn contiguous_range_for_group<'a>( | |||
103 | } | 129 | } |
104 | 130 | ||
105 | // Stop if we find a node that doesn't belong to the group | 131 | // Stop if we find a node that doesn't belong to the group |
106 | if node.kind() != first.kind() { | 132 | if node.kind() != first.kind() || unless(node) { |
107 | break; | 133 | break; |
108 | } | 134 | } |
109 | 135 | ||
@@ -245,6 +271,38 @@ fn main() <fold>{ | |||
245 | } | 271 | } |
246 | 272 | ||
247 | #[test] | 273 | #[test] |
274 | fn test_fold_mods() { | ||
275 | let text = r#" | ||
276 | |||
277 | pub mod foo; | ||
278 | <fold>mod after_pub; | ||
279 | mod after_pub_next;</fold> | ||
280 | |||
281 | <fold>mod before_pub; | ||
282 | mod before_pub_next;</fold> | ||
283 | pub mod bar; | ||
284 | |||
285 | mod not_folding_single; | ||
286 | pub mod foobar; | ||
287 | pub not_folding_single_next; | ||
288 | |||
289 | <fold>#[cfg(test)] | ||
290 | mod with_attribute; | ||
291 | mod with_attribute_next;</fold> | ||
292 | |||
293 | fn main() <fold>{ | ||
294 | }</fold>"#; | ||
295 | |||
296 | let folds = &[ | ||
297 | FoldKind::Mods, | ||
298 | FoldKind::Mods, | ||
299 | FoldKind::Mods, | ||
300 | FoldKind::Block, | ||
301 | ]; | ||
302 | do_check(text, folds); | ||
303 | } | ||
304 | |||
305 | #[test] | ||
248 | fn test_fold_import_groups() { | 306 | fn test_fold_import_groups() { |
249 | let text = r#" | 307 | let text = r#" |
250 | <fold>use std::str; | 308 | <fold>use std::str; |
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index c0fe0216d..8ea9edc84 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs | |||
@@ -369,6 +369,7 @@ pub fn handle_folding_range( | |||
369 | let kind = match fold.kind { | 369 | let kind = match fold.kind { |
370 | FoldKind::Comment => Some(FoldingRangeKind::Comment), | 370 | FoldKind::Comment => Some(FoldingRangeKind::Comment), |
371 | FoldKind::Imports => Some(FoldingRangeKind::Imports), | 371 | FoldKind::Imports => Some(FoldingRangeKind::Imports), |
372 | FoldKind::Mods => None, | ||
372 | FoldKind::Block => None, | 373 | FoldKind::Block => None, |
373 | }; | 374 | }; |
374 | let range = fold.range.conv_with(&line_index); | 375 | let range = fold.range.conv_with(&line_index); |