diff options
Diffstat (limited to 'crates/ra_editor/src')
-rw-r--r-- | crates/ra_editor/src/code_actions.rs | 4 | ||||
-rw-r--r-- | crates/ra_editor/src/completion.rs | 2 | ||||
-rw-r--r-- | crates/ra_editor/src/edit.rs | 2 | ||||
-rw-r--r-- | crates/ra_editor/src/folding_ranges.rs | 177 | ||||
-rw-r--r-- | crates/ra_editor/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ra_editor/src/line_index.rs | 4 | ||||
-rw-r--r-- | crates/ra_editor/src/scope/fn_scope.rs | 4 | ||||
-rw-r--r-- | crates/ra_editor/src/symbols.rs | 4 | ||||
-rw-r--r-- | crates/ra_editor/src/test_utils.rs | 4 | ||||
-rw-r--r-- | crates/ra_editor/src/typing.rs | 4 |
10 files changed, 126 insertions, 81 deletions
diff --git a/crates/ra_editor/src/code_actions.rs b/crates/ra_editor/src/code_actions.rs index 216d592ff..7b0a48c81 100644 --- a/crates/ra_editor/src/code_actions.rs +++ b/crates/ra_editor/src/code_actions.rs | |||
@@ -11,7 +11,7 @@ use ra_syntax::{ | |||
11 | }, | 11 | }, |
12 | }; | 12 | }; |
13 | 13 | ||
14 | use {EditBuilder, Edit, find_node_at_offset}; | 14 | use crate::{EditBuilder, Edit, find_node_at_offset}; |
15 | 15 | ||
16 | #[derive(Debug)] | 16 | #[derive(Debug)] |
17 | pub struct LocalEdit { | 17 | pub struct LocalEdit { |
@@ -136,7 +136,7 @@ fn non_trivia_sibling(node: SyntaxNodeRef, direction: Direction) -> Option<Synta | |||
136 | #[cfg(test)] | 136 | #[cfg(test)] |
137 | mod tests { | 137 | mod tests { |
138 | use super::*; | 138 | use super::*; |
139 | use test_utils::{check_action, check_action_range}; | 139 | use crate::test_utils::{check_action, check_action_range}; |
140 | 140 | ||
141 | #[test] | 141 | #[test] |
142 | fn test_swap_comma() { | 142 | fn test_swap_comma() { |
diff --git a/crates/ra_editor/src/completion.rs b/crates/ra_editor/src/completion.rs index 20b8484b3..b6095dca9 100644 --- a/crates/ra_editor/src/completion.rs +++ b/crates/ra_editor/src/completion.rs | |||
@@ -9,7 +9,7 @@ use ra_syntax::{ | |||
9 | text_utils::is_subrange, | 9 | text_utils::is_subrange, |
10 | }; | 10 | }; |
11 | 11 | ||
12 | use { | 12 | use crate::{ |
13 | AtomEdit, find_node_at_offset, | 13 | AtomEdit, find_node_at_offset, |
14 | scope::{FnScopes, ModuleScope}, | 14 | scope::{FnScopes, ModuleScope}, |
15 | }; | 15 | }; |
diff --git a/crates/ra_editor/src/edit.rs b/crates/ra_editor/src/edit.rs index 2839ac20a..46e687319 100644 --- a/crates/ra_editor/src/edit.rs +++ b/crates/ra_editor/src/edit.rs | |||
@@ -1,4 +1,4 @@ | |||
1 | use {TextRange, TextUnit}; | 1 | use crate::{TextRange, TextUnit}; |
2 | use ra_syntax::{ | 2 | use ra_syntax::{ |
3 | AtomEdit, | 3 | AtomEdit, |
4 | text_utils::contains_offset_nonstrict, | 4 | text_utils::contains_offset_nonstrict, |
diff --git a/crates/ra_editor/src/folding_ranges.rs b/crates/ra_editor/src/folding_ranges.rs index 3aabd54ae..a1699d449 100644 --- a/crates/ra_editor/src/folding_ranges.rs +++ b/crates/ra_editor/src/folding_ranges.rs | |||
@@ -1,8 +1,10 @@ | |||
1 | use rustc_hash::FxHashSet; | 1 | use rustc_hash::FxHashSet; |
2 | 2 | ||
3 | use ra_syntax::{ | 3 | use ra_syntax::{ |
4 | ast, | ||
5 | AstNode, | ||
4 | File, TextRange, SyntaxNodeRef, | 6 | File, TextRange, SyntaxNodeRef, |
5 | SyntaxKind, | 7 | SyntaxKind::{self, *}, |
6 | Direction, | 8 | Direction, |
7 | }; | 9 | }; |
8 | 10 | ||
@@ -20,67 +22,97 @@ pub struct Fold { | |||
20 | 22 | ||
21 | pub fn folding_ranges(file: &File) -> Vec<Fold> { | 23 | pub fn folding_ranges(file: &File) -> Vec<Fold> { |
22 | let mut res = vec![]; | 24 | let mut res = vec![]; |
23 | let mut visited = FxHashSet::default(); | 25 | let mut visited_comments = FxHashSet::default(); |
24 | 26 | ||
25 | for node in file.syntax().descendants() { | 27 | for node in file.syntax().descendants() { |
26 | if visited.contains(&node) { | 28 | // Fold items that span multiple lines |
29 | if let Some(kind) = fold_kind(node.kind()) { | ||
30 | if has_newline(node) { | ||
31 | res.push(Fold { range: node.range(), kind }); | ||
32 | } | ||
33 | } | ||
34 | |||
35 | // Also fold groups of comments | ||
36 | if visited_comments.contains(&node) { | ||
27 | continue; | 37 | continue; |
28 | } | 38 | } |
39 | if node.kind() == COMMENT { | ||
40 | contiguous_range_for_comment(node, &mut visited_comments) | ||
41 | .map(|range| res.push(Fold { range, kind: FoldKind::Comment })); | ||
42 | } | ||
43 | } | ||
44 | |||
45 | res | ||
46 | } | ||
29 | 47 | ||
30 | let range_and_kind = match node.kind() { | 48 | fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> { |
31 | SyntaxKind::COMMENT => ( | 49 | match kind { |
32 | contiguous_range_for(SyntaxKind::COMMENT, node, &mut visited), | 50 | COMMENT => Some(FoldKind::Comment), |
33 | Some(FoldKind::Comment), | 51 | USE_ITEM => Some(FoldKind::Imports), |
34 | ), | 52 | _ => None |
35 | SyntaxKind::USE_ITEM => ( | 53 | } |
36 | contiguous_range_for(SyntaxKind::USE_ITEM, node, &mut visited), | 54 | } |
37 | Some(FoldKind::Imports), | 55 | |
38 | ), | 56 | fn has_newline( |
39 | _ => (None, None), | 57 | node: SyntaxNodeRef, |
40 | }; | 58 | ) -> bool { |
41 | 59 | for descendant in node.descendants() { | |
42 | match range_and_kind { | 60 | if let Some(ws) = ast::Whitespace::cast(descendant) { |
43 | (Some(range), Some(kind)) => { | 61 | if ws.has_newlines() { |
44 | res.push(Fold { | 62 | return true; |
45 | range: range, | 63 | } |
46 | kind: kind | 64 | } else if let Some(comment) = ast::Comment::cast(descendant) { |
47 | }); | 65 | if comment.has_newlines() { |
66 | return true; | ||
48 | } | 67 | } |
49 | _ => {} | ||
50 | } | 68 | } |
51 | } | 69 | } |
52 | 70 | ||
53 | res | 71 | false |
54 | } | 72 | } |
55 | 73 | ||
56 | fn contiguous_range_for<'a>( | 74 | fn contiguous_range_for_comment<'a>( |
57 | kind: SyntaxKind, | 75 | first: SyntaxNodeRef<'a>, |
58 | node: SyntaxNodeRef<'a>, | ||
59 | visited: &mut FxHashSet<SyntaxNodeRef<'a>>, | 76 | visited: &mut FxHashSet<SyntaxNodeRef<'a>>, |
60 | ) -> Option<TextRange> { | 77 | ) -> Option<TextRange> { |
61 | visited.insert(node); | 78 | visited.insert(first); |
62 | 79 | ||
63 | let left = node; | 80 | // Only fold comments of the same flavor |
64 | let mut right = node; | 81 | let group_flavor = ast::Comment::cast(first)?.flavor(); |
65 | for node in node.siblings(Direction::Next) { | 82 | |
66 | visited.insert(node); | 83 | let mut last = first; |
67 | match node.kind() { | 84 | for node in first.siblings(Direction::Next) { |
68 | SyntaxKind::WHITESPACE if !node.leaf_text().unwrap().as_str().contains("\n\n") => (), | 85 | if let Some(ws) = ast::Whitespace::cast(node) { |
69 | k => { | 86 | // There is a blank line, which means the group ends here |
70 | if k == kind { | 87 | if ws.count_newlines_lazy().take(2).count() == 2 { |
71 | right = node | 88 | break; |
72 | } else { | 89 | } |
73 | break; | 90 | |
74 | } | 91 | // Ignore whitespace without blank lines |
92 | continue; | ||
93 | } | ||
94 | |||
95 | match ast::Comment::cast(node) { | ||
96 | Some(next_comment) if next_comment.flavor() == group_flavor => { | ||
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 | ||
75 | } | 105 | } |
76 | } | 106 | } |
77 | } | 107 | } |
78 | if left != right { | 108 | |
109 | if first != last { | ||
79 | Some(TextRange::from_to( | 110 | Some(TextRange::from_to( |
80 | left.range().start(), | 111 | first.range().start(), |
81 | right.range().end(), | 112 | last.range().end(), |
82 | )) | 113 | )) |
83 | } else { | 114 | } else { |
115 | // The group consists of only one element, therefore it cannot be folded | ||
84 | None | 116 | None |
85 | } | 117 | } |
86 | } | 118 | } |
@@ -88,52 +120,65 @@ fn contiguous_range_for<'a>( | |||
88 | #[cfg(test)] | 120 | #[cfg(test)] |
89 | mod tests { | 121 | mod tests { |
90 | use super::*; | 122 | use super::*; |
123 | use test_utils::extract_ranges; | ||
124 | |||
125 | fn do_check(text: &str, fold_kinds: &[FoldKind]) { | ||
126 | let (ranges, text) = extract_ranges(text); | ||
127 | let file = File::parse(&text); | ||
128 | let folds = folding_ranges(&file); | ||
129 | |||
130 | assert_eq!(folds.len(), ranges.len()); | ||
131 | for ((fold, range), fold_kind) in folds.into_iter().zip(ranges.into_iter()).zip(fold_kinds.into_iter()) { | ||
132 | assert_eq!(fold.range.start(), range.start()); | ||
133 | assert_eq!(fold.range.end(), range.end()); | ||
134 | assert_eq!(&fold.kind, fold_kind); | ||
135 | } | ||
136 | } | ||
91 | 137 | ||
92 | #[test] | 138 | #[test] |
93 | fn test_fold_comments() { | 139 | fn test_fold_comments() { |
94 | let text = r#" | 140 | let text = r#" |
95 | // Hello | 141 | <|>// Hello |
96 | // this is a multiline | 142 | // this is a multiline |
97 | // comment | 143 | // comment |
98 | // | 144 | //<|> |
99 | 145 | ||
100 | // But this is not | 146 | // But this is not |
101 | 147 | ||
102 | fn main() { | 148 | fn main() { |
103 | // We should | 149 | <|>// We should |
104 | // also | 150 | // also |
105 | // fold | 151 | // fold |
106 | // this one. | 152 | // this one.<|> |
153 | <|>//! But this one is different | ||
154 | //! because it has another flavor<|> | ||
155 | <|>/* As does this | ||
156 | multiline comment */<|> | ||
107 | }"#; | 157 | }"#; |
108 | 158 | ||
109 | let file = File::parse(&text); | 159 | let fold_kinds = &[ |
110 | let folds = folding_ranges(&file); | 160 | FoldKind::Comment, |
111 | assert_eq!(folds.len(), 2); | 161 | FoldKind::Comment, |
112 | assert_eq!(folds[0].range.start(), 1.into()); | 162 | FoldKind::Comment, |
113 | assert_eq!(folds[0].range.end(), 46.into()); | 163 | FoldKind::Comment, |
114 | assert_eq!(folds[0].kind, FoldKind::Comment); | 164 | ]; |
115 | 165 | do_check(text, fold_kinds); | |
116 | assert_eq!(folds[1].range.start(), 84.into()); | ||
117 | assert_eq!(folds[1].range.end(), 137.into()); | ||
118 | assert_eq!(folds[1].kind, FoldKind::Comment); | ||
119 | } | 166 | } |
120 | 167 | ||
121 | #[test] | 168 | #[test] |
122 | fn test_fold_imports() { | 169 | fn test_fold_imports() { |
123 | let text = r#" | 170 | let text = r#" |
124 | use std::str; | 171 | <|>use std::{ |
125 | use std::vec; | 172 | str, |
126 | use std::io as iop; | 173 | vec, |
174 | io as iop | ||
175 | };<|> | ||
127 | 176 | ||
128 | fn main() { | 177 | fn main() { |
129 | }"#; | 178 | }"#; |
130 | 179 | ||
131 | let file = File::parse(&text); | 180 | let folds = &[FoldKind::Imports]; |
132 | let folds = folding_ranges(&file); | 181 | do_check(text, folds); |
133 | assert_eq!(folds.len(), 1); | ||
134 | assert_eq!(folds[0].range.start(), 1.into()); | ||
135 | assert_eq!(folds[0].range.end(), 48.into()); | ||
136 | assert_eq!(folds[0].kind, FoldKind::Imports); | ||
137 | } | 182 | } |
138 | 183 | ||
139 | 184 | ||
diff --git a/crates/ra_editor/src/lib.rs b/crates/ra_editor/src/lib.rs index 710afc65d..bd61fd191 100644 --- a/crates/ra_editor/src/lib.rs +++ b/crates/ra_editor/src/lib.rs | |||
@@ -164,7 +164,7 @@ pub fn resolve_local_name(file: &File, offset: TextUnit, name_ref: ast::NameRef) | |||
164 | #[cfg(test)] | 164 | #[cfg(test)] |
165 | mod tests { | 165 | mod tests { |
166 | use super::*; | 166 | use super::*; |
167 | use test_utils::{assert_eq_dbg, extract_offset, add_cursor}; | 167 | use crate::test_utils::{assert_eq_dbg, extract_offset, add_cursor}; |
168 | 168 | ||
169 | #[test] | 169 | #[test] |
170 | fn test_highlighting() { | 170 | fn test_highlighting() { |
diff --git a/crates/ra_editor/src/line_index.rs b/crates/ra_editor/src/line_index.rs index 9cd8da3a8..95d64b8a8 100644 --- a/crates/ra_editor/src/line_index.rs +++ b/crates/ra_editor/src/line_index.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | use superslice::Ext; | 1 | use superslice::Ext; |
2 | use ::TextUnit; | 2 | use crate::TextUnit; |
3 | 3 | ||
4 | #[derive(Clone, Debug, Hash)] | 4 | #[derive(Clone, Debug, Hash, PartialEq, Eq)] |
5 | pub struct LineIndex { | 5 | pub struct LineIndex { |
6 | newlines: Vec<TextUnit>, | 6 | newlines: Vec<TextUnit>, |
7 | } | 7 | } |
diff --git a/crates/ra_editor/src/scope/fn_scope.rs b/crates/ra_editor/src/scope/fn_scope.rs index 9a48bda02..99d698b60 100644 --- a/crates/ra_editor/src/scope/fn_scope.rs +++ b/crates/ra_editor/src/scope/fn_scope.rs | |||
@@ -174,7 +174,7 @@ fn compute_expr_scopes(expr: ast::Expr, scopes: &mut FnScopes, scope: ScopeId) { | |||
174 | } | 174 | } |
175 | } | 175 | } |
176 | ast::Expr::LambdaExpr(e) => { | 176 | ast::Expr::LambdaExpr(e) => { |
177 | let mut scope = scopes.new_scope(scope); | 177 | let scope = scopes.new_scope(scope); |
178 | scopes.add_params_bindings(scope, e.param_list()); | 178 | scopes.add_params_bindings(scope, e.param_list()); |
179 | if let Some(body) = e.body() { | 179 | if let Some(body) = e.body() { |
180 | scopes.set_scope(body.syntax(), scope); | 180 | scopes.set_scope(body.syntax(), scope); |
@@ -256,7 +256,7 @@ pub fn resolve_local_name<'a>(name_ref: ast::NameRef, scopes: &'a FnScopes) -> O | |||
256 | mod tests { | 256 | mod tests { |
257 | use super::*; | 257 | use super::*; |
258 | use ra_syntax::File; | 258 | use ra_syntax::File; |
259 | use {find_node_at_offset, test_utils::extract_offset}; | 259 | use crate::{find_node_at_offset, test_utils::extract_offset}; |
260 | 260 | ||
261 | fn do_check(code: &str, expected: &[&str]) { | 261 | fn do_check(code: &str, expected: &[&str]) { |
262 | let (off, code) = extract_offset(code); | 262 | let (off, code) = extract_offset(code); |
diff --git a/crates/ra_editor/src/symbols.rs b/crates/ra_editor/src/symbols.rs index e5cc5ca28..d9e4b2df7 100644 --- a/crates/ra_editor/src/symbols.rs +++ b/crates/ra_editor/src/symbols.rs | |||
@@ -6,7 +6,7 @@ use ra_syntax::{ | |||
6 | walk::{walk, WalkEvent}, | 6 | walk::{walk, WalkEvent}, |
7 | }, | 7 | }, |
8 | }; | 8 | }; |
9 | use TextRange; | 9 | use crate::TextRange; |
10 | 10 | ||
11 | #[derive(Debug, Clone)] | 11 | #[derive(Debug, Clone)] |
12 | pub struct StructureNode { | 12 | pub struct StructureNode { |
@@ -17,7 +17,7 @@ pub struct StructureNode { | |||
17 | pub kind: SyntaxKind, | 17 | pub kind: SyntaxKind, |
18 | } | 18 | } |
19 | 19 | ||
20 | #[derive(Debug, Clone, Hash)] | 20 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
21 | pub struct FileSymbol { | 21 | pub struct FileSymbol { |
22 | pub name: SmolStr, | 22 | pub name: SmolStr, |
23 | pub node_range: TextRange, | 23 | pub node_range: TextRange, |
diff --git a/crates/ra_editor/src/test_utils.rs b/crates/ra_editor/src/test_utils.rs index c4ea4db6c..49eb530d5 100644 --- a/crates/ra_editor/src/test_utils.rs +++ b/crates/ra_editor/src/test_utils.rs | |||
@@ -1,6 +1,6 @@ | |||
1 | use ra_syntax::{File, TextUnit, TextRange}; | 1 | use ra_syntax::{File, TextUnit, TextRange}; |
2 | pub use _test_utils::*; | 2 | pub use crate::_test_utils::*; |
3 | use LocalEdit; | 3 | use crate::LocalEdit; |
4 | 4 | ||
5 | pub fn check_action<F: Fn(&File, TextUnit) -> Option<LocalEdit>> ( | 5 | pub fn check_action<F: Fn(&File, TextUnit) -> Option<LocalEdit>> ( |
6 | before: &str, | 6 | before: &str, |
diff --git a/crates/ra_editor/src/typing.rs b/crates/ra_editor/src/typing.rs index 1dc658f9b..542b9e10b 100644 --- a/crates/ra_editor/src/typing.rs +++ b/crates/ra_editor/src/typing.rs | |||
@@ -10,7 +10,7 @@ use ra_syntax::{ | |||
10 | SyntaxKind::*, | 10 | SyntaxKind::*, |
11 | }; | 11 | }; |
12 | 12 | ||
13 | use {LocalEdit, EditBuilder, find_node_at_offset}; | 13 | use crate::{LocalEdit, EditBuilder, find_node_at_offset}; |
14 | 14 | ||
15 | pub fn join_lines(file: &File, range: TextRange) -> LocalEdit { | 15 | pub fn join_lines(file: &File, range: TextRange) -> LocalEdit { |
16 | let range = if range.is_empty() { | 16 | let range = if range.is_empty() { |
@@ -244,7 +244,7 @@ fn compute_ws(left: SyntaxNodeRef, right: SyntaxNodeRef) -> &'static str { | |||
244 | #[cfg(test)] | 244 | #[cfg(test)] |
245 | mod tests { | 245 | mod tests { |
246 | use super::*; | 246 | use super::*; |
247 | use test_utils::{check_action, extract_range, extract_offset, add_cursor}; | 247 | use crate::test_utils::{check_action, extract_range, extract_offset, add_cursor}; |
248 | 248 | ||
249 | fn check_join_lines(before: &str, after: &str) { | 249 | fn check_join_lines(before: &str, after: &str) { |
250 | check_action(before, after, |file, offset| { | 250 | check_action(before, after, |file, offset| { |