aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_editor/src/folding_ranges.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_editor/src/folding_ranges.rs')
-rw-r--r--crates/ra_editor/src/folding_ranges.rs57
1 files changed, 30 insertions, 27 deletions
diff --git a/crates/ra_editor/src/folding_ranges.rs b/crates/ra_editor/src/folding_ranges.rs
index d45210ec7..8aabb5e0b 100644
--- a/crates/ra_editor/src/folding_ranges.rs
+++ b/crates/ra_editor/src/folding_ranges.rs
@@ -4,7 +4,7 @@ use ra_syntax::{
4 ast, 4 ast,
5 AstNode, 5 AstNode,
6 File, TextRange, SyntaxNodeRef, 6 File, TextRange, SyntaxNodeRef,
7 SyntaxKind, 7 SyntaxKind::{self, *},
8 Direction, 8 Direction,
9}; 9};
10 10
@@ -22,7 +22,7 @@ pub struct Fold {
22 22
23pub fn folding_ranges(file: &File) -> Vec<Fold> { 23pub fn folding_ranges(file: &File) -> Vec<Fold> {
24 let mut res = vec![]; 24 let mut res = vec![];
25 let mut group_members = FxHashSet::default(); 25 let mut visited_comments = FxHashSet::default();
26 26
27 for node in file.syntax().descendants() { 27 for node in file.syntax().descendants() {
28 // Fold items that span multiple lines 28 // Fold items that span multiple lines
@@ -32,17 +32,13 @@ pub fn folding_ranges(file: &File) -> Vec<Fold> {
32 } 32 }
33 } 33 }
34 34
35 // Also fold item *groups* that span multiple lines 35 // Also fold groups of comments
36 36 if visited_comments.contains(&node) {
37 // Note: we need to skip elements of the group that we have already visited,
38 // otherwise there will be folds for the whole group and for its sub groups
39 if group_members.contains(&node) {
40 continue; 37 continue;
41 } 38 }
42 39 if node.kind() == COMMENT {
43 if let Some(kind) = fold_kind(node.kind()) { 40 contiguous_range_for_comment(node, &mut visited_comments)
44 contiguous_range_for_group(node.kind(), node, &mut group_members) 41 .map(|range| res.push(Fold { range, kind: FoldKind::Comment }));
45 .map(|range| res.push(Fold { range, kind }));
46 } 42 }
47 } 43 }
48 44
@@ -51,8 +47,8 @@ pub fn folding_ranges(file: &File) -> Vec<Fold> {
51 47
52fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> { 48fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
53 match kind { 49 match kind {
54 SyntaxKind::COMMENT => Some(FoldKind::Comment), 50 COMMENT => Some(FoldKind::Comment),
55 SyntaxKind::USE_ITEM => Some(FoldKind::Imports), 51 USE_ITEM => Some(FoldKind::Imports),
56 _ => None 52 _ => None
57 } 53 }
58} 54}
@@ -75,17 +71,17 @@ fn has_newline(
75 false 71 false
76} 72}
77 73
78fn contiguous_range_for_group<'a>( 74fn contiguous_range_for_comment<'a>(
79 group_kind: SyntaxKind,
80 first: SyntaxNodeRef<'a>, 75 first: SyntaxNodeRef<'a>,
81 visited: &mut FxHashSet<SyntaxNodeRef<'a>>, 76 visited: &mut FxHashSet<SyntaxNodeRef<'a>>,
82) -> Option<TextRange> { 77) -> Option<TextRange> {
83 visited.insert(first); 78 visited.insert(first);
84 79
85 let mut last = first; 80 // Only fold comments of the same flavor
81 let group_flavor = ast::Comment::cast(first)?.flavor();
86 82
83 let mut last = first;
87 for node in first.siblings(Direction::Next) { 84 for node in first.siblings(Direction::Next) {
88 visited.insert(node);
89 if let Some(ws) = ast::Whitespace::cast(node) { 85 if let Some(ws) = ast::Whitespace::cast(node) {
90 // There is a blank line, which means the group ends here 86 // There is a blank line, which means the group ends here
91 if ws.count_newlines_lazy().take(2).count() == 2 { 87 if ws.count_newlines_lazy().take(2).count() == 2 {
@@ -96,13 +92,18 @@ fn contiguous_range_for_group<'a>(
96 continue; 92 continue;
97 } 93 }
98 94
99 // The group ends when an element of a different kind is reached 95 match ast::Comment::cast(node) {
100 if node.kind() != group_kind { 96 Some(next_comment) if next_comment.flavor() == group_flavor => {
101 break; 97 visited.insert(node);
98 last = node;
99 }
100 // The comment group ends because either:
101 // * An element of a different kind was reached
102 // * A comment of a different flavor was reached
103 _ => {
104 break
105 }
102 } 106 }
103
104 // Keep track of the last node in the group
105 last = node;
106 } 107 }
107 108
108 if first != last { 109 if first != last {
@@ -152,9 +153,11 @@ fn main() {
152 #[test] 153 #[test]
153 fn test_fold_imports() { 154 fn test_fold_imports() {
154 let text = r#" 155 let text = r#"
155use std::str; 156use std::{
156use std::vec; 157 str,
157use std::io as iop; 158 vec,
159 io as iop
160};
158 161
159fn main() { 162fn main() {
160}"#; 163}"#;
@@ -163,7 +166,7 @@ fn main() {
163 let folds = folding_ranges(&file); 166 let folds = folding_ranges(&file);
164 assert_eq!(folds.len(), 1); 167 assert_eq!(folds.len(), 1);
165 assert_eq!(folds[0].range.start(), 1.into()); 168 assert_eq!(folds[0].range.start(), 1.into());
166 assert_eq!(folds[0].range.end(), 48.into()); 169 assert_eq!(folds[0].range.end(), 46.into());
167 assert_eq!(folds[0].kind, FoldKind::Imports); 170 assert_eq!(folds[0].kind, FoldKind::Imports);
168 } 171 }
169 172