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.rs64
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::{
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,14 @@ fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
68 } 82 }
69} 83}
70 84
85fn 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
71fn has_newline(node: &SyntaxNode) -> bool { 93fn 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
116fn 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
281pub mod foo;
282<fold>mod after_pub;
283mod after_pub_next;</fold>
284
285<fold>mod before_pub;
286mod before_pub_next;</fold>
287pub mod bar;
288
289mod not_folding_single;
290pub mod foobar;
291pub not_folding_single_next;
292
293<fold>#[cfg(test)]
294mod with_attribute;
295mod with_attribute_next;</fold>
296
297fn 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;