diff options
Diffstat (limited to 'crates/ra_editor/src/folding_ranges.rs')
-rw-r--r-- | crates/ra_editor/src/folding_ranges.rs | 57 |
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 | ||
23 | pub fn folding_ranges(file: &File) -> Vec<Fold> { | 23 | pub 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 | ||
52 | fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> { | 48 | fn 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 | ||
78 | fn contiguous_range_for_group<'a>( | 74 | fn 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#" |
155 | use std::str; | 156 | use std::{ |
156 | use std::vec; | 157 | str, |
157 | use std::io as iop; | 158 | vec, |
159 | io as iop | ||
160 | }; | ||
158 | 161 | ||
159 | fn main() { | 162 | fn 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 | ||