aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-01-10 12:20:00 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-01-10 12:20:00 +0000
commit9225033cdf16fd9f3f38b3d3482efb0c36698085 (patch)
treeb804cf396e2e6b6d4da6082096f933b445671579 /crates
parentc2b8aa1ce5e5398d981387079e86ff67a5b7e8c0 (diff)
parent8384b2cc38acc6e8c1741e8d2d6a66f74b7f02b3 (diff)
Merge #477
477: Extend selection for list items r=matklad a=hban First PR, criticism welcome! There are a few things I'm not so sure about: * There is now a not-so-small list of "list-like kinds" in extend selection source which maybe should belong somewhere else. * Preferring left comma doesn't seem right IMO for one reason - trailing commas are usually on the right. For example, when array values are broken across multiple lines extending selected value will cover right trailing comma (because it's the only comma on the same line), but when all values are on the same line it will pick left comma. Anyway, currently with this PR it will pick always extend to left comma when possible since that's what issue specified 😃. Closes: #444 Co-authored-by: Hrvoje Ban <[email protected]>
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_ide_api_light/src/extend_selection.rs131
1 files changed, 127 insertions, 4 deletions
diff --git a/crates/ra_ide_api_light/src/extend_selection.rs b/crates/ra_ide_api_light/src/extend_selection.rs
index 08cae5a51..db93db208 100644
--- a/crates/ra_ide_api_light/src/extend_selection.rs
+++ b/crates/ra_ide_api_light/src/extend_selection.rs
@@ -6,6 +6,21 @@ use ra_syntax::{
6 6
7pub fn extend_selection(root: &SyntaxNode, range: TextRange) -> Option<TextRange> { 7pub fn extend_selection(root: &SyntaxNode, range: TextRange) -> Option<TextRange> {
8 let string_kinds = [COMMENT, STRING, RAW_STRING, BYTE_STRING, RAW_BYTE_STRING]; 8 let string_kinds = [COMMENT, STRING, RAW_STRING, BYTE_STRING, RAW_BYTE_STRING];
9 let list_kinds = [
10 FIELD_PAT_LIST,
11 MATCH_ARM_LIST,
12 NAMED_FIELD_LIST,
13 NAMED_FIELD_DEF_LIST,
14 POS_FIELD_LIST,
15 ENUM_VARIANT_LIST,
16 USE_TREE_LIST,
17 TYPE_PARAM_LIST,
18 TYPE_ARG_LIST,
19 PARAM_LIST,
20 ARG_LIST,
21 ARRAY_EXPR,
22 ];
23
9 if range.is_empty() { 24 if range.is_empty() {
10 let offset = range.start(); 25 let offset = range.start();
11 let mut leaves = find_leaf_at_offset(root, offset); 26 let mut leaves = find_leaf_at_offset(root, offset);
@@ -26,9 +41,25 @@ pub fn extend_selection(root: &SyntaxNode, range: TextRange) -> Option<TextRange
26 return Some(leaf_range); 41 return Some(leaf_range);
27 }; 42 };
28 let node = find_covering_node(root, range); 43 let node = find_covering_node(root, range);
29 if string_kinds.contains(&node.kind()) && range == node.range() { 44
30 if let Some(range) = extend_comments(node) { 45 // Using shallowest node with same range allows us to traverse siblings.
31 return Some(range); 46 let node = node
47 .ancestors()
48 .take_while(|n| n.range() == node.range())
49 .last()
50 .unwrap();
51
52 if range == node.range() {
53 if string_kinds.contains(&node.kind()) {
54 if let Some(range) = extend_comments(node) {
55 return Some(range);
56 }
57 }
58
59 if node.parent().map(|n| list_kinds.contains(&n.kind())) == Some(true) {
60 if let Some(range) = extend_list_item(node) {
61 return Some(range);
62 }
32 } 63 }
33 } 64 }
34 65
@@ -99,6 +130,45 @@ fn pick_best<'a>(l: &'a SyntaxNode, r: &'a SyntaxNode) -> &'a SyntaxNode {
99 } 130 }
100} 131}
101 132
133/// Extend list item selection to include nearby comma and whitespace.
134fn extend_list_item(node: &SyntaxNode) -> Option<TextRange> {
135 fn is_single_line_ws(node: &SyntaxNode) -> bool {
136 node.kind() == WHITESPACE && !node.leaf_text().unwrap().contains('\n')
137 }
138
139 fn nearby_comma(node: &SyntaxNode, dir: Direction) -> Option<&SyntaxNode> {
140 node.siblings(dir)
141 .skip(1)
142 .skip_while(|node| is_single_line_ws(node))
143 .next()
144 .filter(|node| node.kind() == COMMA)
145 }
146
147 if let Some(comma_node) = nearby_comma(node, Direction::Prev) {
148 return Some(TextRange::from_to(
149 comma_node.range().start(),
150 node.range().end(),
151 ));
152 }
153
154 if let Some(comma_node) = nearby_comma(node, Direction::Next) {
155 // Include any following whitespace when comma if after list item.
156 let final_node = comma_node
157 .siblings(Direction::Next)
158 .skip(1)
159 .next()
160 .filter(|node| is_single_line_ws(node))
161 .unwrap_or(comma_node);
162
163 return Some(TextRange::from_to(
164 node.range().start(),
165 final_node.range().end(),
166 ));
167 }
168
169 return None;
170}
171
102fn extend_comments(node: &SyntaxNode) -> Option<TextRange> { 172fn extend_comments(node: &SyntaxNode) -> Option<TextRange> {
103 let prev = adj_comments(node, Direction::Prev); 173 let prev = adj_comments(node, Direction::Prev);
104 let next = adj_comments(node, Direction::Next); 174 let next = adj_comments(node, Direction::Next);
@@ -145,7 +215,60 @@ mod tests {
145 } 215 }
146 216
147 #[test] 217 #[test]
148 fn test_extend_selection_start_of_the_lind() { 218 fn test_extend_selection_list() {
219 do_check(r#"fn foo(<|>x: i32) {}"#, &["x", "x: i32"]);
220 do_check(
221 r#"fn foo(<|>x: i32, y: i32) {}"#,
222 &["x", "x: i32", "x: i32, "],
223 );
224 do_check(
225 r#"fn foo(<|>x: i32,y: i32) {}"#,
226 &["x", "x: i32", "x: i32,"],
227 );
228 do_check(
229 r#"fn foo(x: i32, <|>y: i32) {}"#,
230 &["y", "y: i32", ", y: i32"],
231 );
232 do_check(
233 r#"fn foo(x: i32, <|>y: i32, ) {}"#,
234 &["y", "y: i32", ", y: i32"],
235 );
236 do_check(
237 r#"fn foo(x: i32,<|>y: i32) {}"#,
238 &["y", "y: i32", ",y: i32"],
239 );
240
241 do_check(
242 r#"const FOO: [usize; 2] = [ 22<|> , 33];"#,
243 &["22", "22 , "],
244 );
245 do_check(r#"const FOO: [usize; 2] = [ 22 , 33<|>];"#, &["33", ", 33"]);
246 do_check(
247 r#"const FOO: [usize; 2] = [ 22 , 33<|> ,];"#,
248 &["33", ", 33"],
249 );
250
251 do_check(
252 r#"
253const FOO: [usize; 2] = [
254 22,
255 <|>33,
256]"#,
257 &["33", "33,"],
258 );
259
260 do_check(
261 r#"
262const FOO: [usize; 2] = [
263 22
264 , 33<|>,
265]"#,
266 &["33", ", 33"],
267 );
268 }
269
270 #[test]
271 fn test_extend_selection_start_of_the_line() {
149 do_check( 272 do_check(
150 r#" 273 r#"
151impl S { 274impl S {