aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_editor/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_editor/src')
-rw-r--r--crates/ra_editor/src/code_actions.rs4
-rw-r--r--crates/ra_editor/src/completion.rs2
-rw-r--r--crates/ra_editor/src/edit.rs2
-rw-r--r--crates/ra_editor/src/folding_ranges.rs177
-rw-r--r--crates/ra_editor/src/lib.rs2
-rw-r--r--crates/ra_editor/src/line_index.rs4
-rw-r--r--crates/ra_editor/src/scope/fn_scope.rs4
-rw-r--r--crates/ra_editor/src/symbols.rs4
-rw-r--r--crates/ra_editor/src/test_utils.rs4
-rw-r--r--crates/ra_editor/src/typing.rs4
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
14use {EditBuilder, Edit, find_node_at_offset}; 14use crate::{EditBuilder, Edit, find_node_at_offset};
15 15
16#[derive(Debug)] 16#[derive(Debug)]
17pub struct LocalEdit { 17pub struct LocalEdit {
@@ -136,7 +136,7 @@ fn non_trivia_sibling(node: SyntaxNodeRef, direction: Direction) -> Option<Synta
136#[cfg(test)] 136#[cfg(test)]
137mod tests { 137mod 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
12use { 12use 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 @@
1use {TextRange, TextUnit}; 1use crate::{TextRange, TextUnit};
2use ra_syntax::{ 2use 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 @@
1use rustc_hash::FxHashSet; 1use rustc_hash::FxHashSet;
2 2
3use ra_syntax::{ 3use 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
21pub fn folding_ranges(file: &File) -> Vec<Fold> { 23pub 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() { 48fn 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 ), 56fn 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
56fn contiguous_range_for<'a>( 74fn 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)]
89mod tests { 121mod 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
102fn main() { 148fn 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#"
124use std::str; 171<|>use std::{
125use std::vec; 172 str,
126use std::io as iop; 173 vec,
174 io as iop
175};<|>
127 176
128fn main() { 177fn 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)]
165mod tests { 165mod 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 @@
1use superslice::Ext; 1use superslice::Ext;
2use ::TextUnit; 2use crate::TextUnit;
3 3
4#[derive(Clone, Debug, Hash)] 4#[derive(Clone, Debug, Hash, PartialEq, Eq)]
5pub struct LineIndex { 5pub 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
256mod tests { 256mod 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};
9use TextRange; 9use crate::TextRange;
10 10
11#[derive(Debug, Clone)] 11#[derive(Debug, Clone)]
12pub struct StructureNode { 12pub 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)]
21pub struct FileSymbol { 21pub 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 @@
1use ra_syntax::{File, TextUnit, TextRange}; 1use ra_syntax::{File, TextUnit, TextRange};
2pub use _test_utils::*; 2pub use crate::_test_utils::*;
3use LocalEdit; 3use crate::LocalEdit;
4 4
5pub fn check_action<F: Fn(&File, TextUnit) -> Option<LocalEdit>> ( 5pub 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
13use {LocalEdit, EditBuilder, find_node_at_offset}; 13use crate::{LocalEdit, EditBuilder, find_node_at_offset};
14 14
15pub fn join_lines(file: &File, range: TextRange) -> LocalEdit { 15pub 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)]
245mod tests { 245mod 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| {