aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api_light
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_api_light')
-rw-r--r--crates/ra_ide_api_light/src/folding_ranges.rs60
1 files changed, 59 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::{
9pub enum FoldKind { 9pub 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
85fn has_visibility(node: &SyntaxNode) -> bool {
86 return node.descendants().any(|n| n.kind() == VISIBILITY);
87}
88
71fn has_newline(node: &SyntaxNode) -> bool { 89fn 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
112fn 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
277pub mod foo;
278<fold>mod after_pub;
279mod after_pub_next;</fold>
280
281<fold>mod before_pub;
282mod before_pub_next;</fold>
283pub mod bar;
284
285mod not_folding_single;
286pub mod foobar;
287pub not_folding_single_next;
288
289<fold>#[cfg(test)]
290mod with_attribute;
291mod with_attribute_next;</fold>
292
293fn 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;