diff options
Diffstat (limited to 'crates/ide/src')
-rw-r--r-- | crates/ide/src/move_item.rs | 114 |
1 files changed, 102 insertions, 12 deletions
diff --git a/crates/ide/src/move_item.rs b/crates/ide/src/move_item.rs index 906d0f268..de4e57b6a 100644 --- a/crates/ide/src/move_item.rs +++ b/crates/ide/src/move_item.rs | |||
@@ -2,7 +2,10 @@ use std::iter::once; | |||
2 | 2 | ||
3 | use hir::Semantics; | 3 | use hir::Semantics; |
4 | use ide_db::{base_db::FileRange, RootDatabase}; | 4 | use ide_db::{base_db::FileRange, RootDatabase}; |
5 | use syntax::{algo, AstNode, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode}; | 5 | use itertools::Itertools; |
6 | use syntax::{ | ||
7 | algo, ast, match_ast, AstNode, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, TextRange, | ||
8 | }; | ||
6 | use text_edit::{TextEdit, TextEditBuilder}; | 9 | use text_edit::{TextEdit, TextEditBuilder}; |
7 | 10 | ||
8 | pub enum Direction { | 11 | pub enum Direction { |
@@ -29,16 +32,17 @@ pub(crate) fn move_item( | |||
29 | let file = sema.parse(range.file_id); | 32 | let file = sema.parse(range.file_id); |
30 | 33 | ||
31 | let item = file.syntax().covering_element(range.range); | 34 | let item = file.syntax().covering_element(range.range); |
32 | find_ancestors(item, direction) | 35 | find_ancestors(item, direction, range.range) |
33 | } | 36 | } |
34 | 37 | ||
35 | fn find_ancestors(item: SyntaxElement, direction: Direction) -> Option<TextEdit> { | 38 | fn find_ancestors(item: SyntaxElement, direction: Direction, range: TextRange) -> Option<TextEdit> { |
36 | let root = match item { | 39 | let root = match item { |
37 | NodeOrToken::Node(node) => node, | 40 | NodeOrToken::Node(node) => node, |
38 | NodeOrToken::Token(token) => token.parent()?, | 41 | NodeOrToken::Token(token) => token.parent()?, |
39 | }; | 42 | }; |
40 | 43 | ||
41 | let movable = [ | 44 | let movable = [ |
45 | SyntaxKind::ARG_LIST, | ||
42 | SyntaxKind::MATCH_ARM, | 46 | SyntaxKind::MATCH_ARM, |
43 | SyntaxKind::PARAM, | 47 | SyntaxKind::PARAM, |
44 | SyntaxKind::LET_STMT, | 48 | SyntaxKind::LET_STMT, |
@@ -64,16 +68,39 @@ fn find_ancestors(item: SyntaxElement, direction: Direction) -> Option<TextEdit> | |||
64 | .chain(root.ancestors()) | 68 | .chain(root.ancestors()) |
65 | .find(|ancestor| movable.contains(&ancestor.kind()))?; | 69 | .find(|ancestor| movable.contains(&ancestor.kind()))?; |
66 | 70 | ||
67 | move_in_direction(&ancestor, direction) | 71 | move_in_direction(&ancestor, direction, range) |
68 | } | 72 | } |
69 | 73 | ||
70 | fn move_in_direction(node: &SyntaxNode, direction: Direction) -> Option<TextEdit> { | 74 | fn move_in_direction( |
71 | let sibling = match direction { | 75 | node: &SyntaxNode, |
72 | Direction::Up => node.prev_sibling(), | 76 | direction: Direction, |
73 | Direction::Down => node.next_sibling(), | 77 | range: TextRange, |
74 | }?; | 78 | ) -> Option<TextEdit> { |
79 | match_ast! { | ||
80 | match node { | ||
81 | ast::ArgList(it) => swap_sibling_in_list(it.args(), range, direction), | ||
82 | _ => Some(replace_nodes(node, &match direction { | ||
83 | Direction::Up => node.prev_sibling(), | ||
84 | Direction::Down => node.next_sibling(), | ||
85 | }?)) | ||
86 | } | ||
87 | } | ||
88 | } | ||
75 | 89 | ||
76 | Some(replace_nodes(node, &sibling)) | 90 | fn swap_sibling_in_list<'i, A: AstNode + Clone, I: Iterator<Item = A>>( |
91 | list: I, | ||
92 | range: TextRange, | ||
93 | direction: Direction, | ||
94 | ) -> Option<TextEdit> { | ||
95 | let (l, r) = list | ||
96 | .tuple_windows() | ||
97 | .filter(|(l, r)| match direction { | ||
98 | Direction::Up => r.syntax().text_range().contains_range(range), | ||
99 | Direction::Down => l.syntax().text_range().contains_range(range), | ||
100 | }) | ||
101 | .next()?; | ||
102 | |||
103 | Some(replace_nodes(l.syntax(), r.syntax())) | ||
77 | } | 104 | } |
78 | 105 | ||
79 | fn replace_nodes(first: &SyntaxNode, second: &SyntaxNode) -> TextEdit { | 106 | fn replace_nodes(first: &SyntaxNode, second: &SyntaxNode) -> TextEdit { |
@@ -304,7 +331,7 @@ use std::vec::Vec; | |||
304 | } | 331 | } |
305 | 332 | ||
306 | #[test] | 333 | #[test] |
307 | fn moves_match_expr_up() { | 334 | fn test_moves_match_expr_up() { |
308 | check( | 335 | check( |
309 | r#" | 336 | r#" |
310 | fn main() { | 337 | fn main() { |
@@ -331,7 +358,7 @@ fn main() { | |||
331 | } | 358 | } |
332 | 359 | ||
333 | #[test] | 360 | #[test] |
334 | fn moves_param_up() { | 361 | fn test_moves_param_up() { |
335 | check( | 362 | check( |
336 | r#" | 363 | r#" |
337 | fn test(one: i32, two$0$0: u32) {} | 364 | fn test(one: i32, two$0$0: u32) {} |
@@ -352,6 +379,69 @@ fn main() { | |||
352 | } | 379 | } |
353 | 380 | ||
354 | #[test] | 381 | #[test] |
382 | fn test_moves_arg_up() { | ||
383 | check( | ||
384 | r#" | ||
385 | fn test(one: i32, two: u32) {} | ||
386 | |||
387 | fn main() { | ||
388 | test(123, 456$0$0); | ||
389 | } | ||
390 | "#, | ||
391 | expect![[r#" | ||
392 | fn test(one: i32, two: u32) {} | ||
393 | |||
394 | fn main() { | ||
395 | test(456, 123); | ||
396 | } | ||
397 | "#]], | ||
398 | Direction::Up, | ||
399 | ); | ||
400 | } | ||
401 | |||
402 | #[test] | ||
403 | fn test_moves_arg_down() { | ||
404 | check( | ||
405 | r#" | ||
406 | fn test(one: i32, two: u32) {} | ||
407 | |||
408 | fn main() { | ||
409 | test(123$0$0, 456); | ||
410 | } | ||
411 | "#, | ||
412 | expect![[r#" | ||
413 | fn test(one: i32, two: u32) {} | ||
414 | |||
415 | fn main() { | ||
416 | test(456, 123); | ||
417 | } | ||
418 | "#]], | ||
419 | Direction::Down, | ||
420 | ); | ||
421 | } | ||
422 | |||
423 | #[test] | ||
424 | fn test_nowhere_to_move_arg() { | ||
425 | check( | ||
426 | r#" | ||
427 | fn test(one: i32, two: u32) {} | ||
428 | |||
429 | fn main() { | ||
430 | test(123$0$0, 456); | ||
431 | } | ||
432 | "#, | ||
433 | expect![[r#" | ||
434 | fn test(one: i32, two: u32) {} | ||
435 | |||
436 | fn main() { | ||
437 | test(123, 456); | ||
438 | } | ||
439 | "#]], | ||
440 | Direction::Up, | ||
441 | ); | ||
442 | } | ||
443 | |||
444 | #[test] | ||
355 | fn test_prioritizes_trait_items() { | 445 | fn test_prioritizes_trait_items() { |
356 | check( | 446 | check( |
357 | r#" | 447 | r#" |