diff options
-rw-r--r-- | crates/ra_assists/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ra_assists/src/move_guard_to_arm_body.rs | 115 | ||||
-rw-r--r-- | docs/user/features.md | 18 |
3 files changed, 135 insertions, 0 deletions
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index 4c330c907..a2998ae59 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs | |||
@@ -101,6 +101,7 @@ mod split_import; | |||
101 | mod remove_dbg; | 101 | mod remove_dbg; |
102 | pub mod auto_import; | 102 | pub mod auto_import; |
103 | mod add_missing_impl_members; | 103 | mod add_missing_impl_members; |
104 | mod move_guard_to_arm_body; | ||
104 | 105 | ||
105 | fn all_assists<DB: HirDatabase>() -> &'static [fn(AssistCtx<DB>) -> Option<Assist>] { | 106 | fn all_assists<DB: HirDatabase>() -> &'static [fn(AssistCtx<DB>) -> Option<Assist>] { |
106 | &[ | 107 | &[ |
@@ -120,6 +121,7 @@ fn all_assists<DB: HirDatabase>() -> &'static [fn(AssistCtx<DB>) -> Option<Assis | |||
120 | add_missing_impl_members::add_missing_impl_members, | 121 | add_missing_impl_members::add_missing_impl_members, |
121 | add_missing_impl_members::add_missing_default_members, | 122 | add_missing_impl_members::add_missing_default_members, |
122 | inline_local_variable::inline_local_varialbe, | 123 | inline_local_variable::inline_local_varialbe, |
124 | move_guard_to_arm_body::move_guard_to_arm_body, | ||
123 | ] | 125 | ] |
124 | } | 126 | } |
125 | 127 | ||
diff --git a/crates/ra_assists/src/move_guard_to_arm_body.rs b/crates/ra_assists/src/move_guard_to_arm_body.rs new file mode 100644 index 000000000..a8ca19f5d --- /dev/null +++ b/crates/ra_assists/src/move_guard_to_arm_body.rs | |||
@@ -0,0 +1,115 @@ | |||
1 | use hir::db::HirDatabase; | ||
2 | use ra_syntax::{ | ||
3 | TextUnit, | ||
4 | SyntaxElement, | ||
5 | ast::{MatchArm, AstNode, AstToken}, | ||
6 | ast, | ||
7 | }; | ||
8 | |||
9 | use crate::{AssistCtx, Assist, AssistId}; | ||
10 | |||
11 | pub(crate) fn move_guard_to_arm_body(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | ||
12 | let match_arm = ctx.node_at_offset::<MatchArm>()?; | ||
13 | let guard = match_arm.guard()?; | ||
14 | let space_before_guard = guard.syntax().prev_sibling_or_token(); | ||
15 | |||
16 | let guard_conditions = guard.expr()?; | ||
17 | let arm_expr = match_arm.expr()?; | ||
18 | let buf = format!("if {} {{ {} }}", guard_conditions.syntax().text(), arm_expr.syntax().text()); | ||
19 | |||
20 | ctx.add_action(AssistId("move_guard_to_arm_body"), "move guard to arm body", |edit| { | ||
21 | edit.target(guard.syntax().range()); | ||
22 | let offseting_amount = match space_before_guard { | ||
23 | Some(SyntaxElement::Token(tok)) => { | ||
24 | if let Some(_) = ast::Whitespace::cast(tok) { | ||
25 | let ele = space_before_guard.unwrap().range(); | ||
26 | edit.delete(ele); | ||
27 | ele.len() | ||
28 | } else { | ||
29 | TextUnit::from(0) | ||
30 | } | ||
31 | } | ||
32 | _ => TextUnit::from(0), | ||
33 | }; | ||
34 | |||
35 | edit.delete(guard.syntax().range()); | ||
36 | edit.replace_node_and_indent(arm_expr.syntax(), buf); | ||
37 | edit.set_cursor(arm_expr.syntax().range().start() + TextUnit::from(3) - offseting_amount); | ||
38 | }); | ||
39 | ctx.build() | ||
40 | } | ||
41 | |||
42 | #[cfg(test)] | ||
43 | mod tests { | ||
44 | use super::*; | ||
45 | |||
46 | use crate::helpers::{ check_assist, check_assist_target }; | ||
47 | |||
48 | #[test] | ||
49 | fn move_guard_to_arm_body_target() { | ||
50 | check_assist_target( | ||
51 | move_guard_to_arm_body, | ||
52 | r#" | ||
53 | fn f() { | ||
54 | let t = 'a'; | ||
55 | let chars = "abcd"; | ||
56 | match t { | ||
57 | '\r' <|>if chars.clone().next() == Some('\n') => false, | ||
58 | _ => true | ||
59 | } | ||
60 | } | ||
61 | "#, | ||
62 | r#"if chars.clone().next() == Some('\n')"#, | ||
63 | ); | ||
64 | } | ||
65 | |||
66 | #[test] | ||
67 | fn move_guard_to_arm_body_works() { | ||
68 | check_assist( | ||
69 | move_guard_to_arm_body, | ||
70 | r#" | ||
71 | fn f() { | ||
72 | let t = 'a'; | ||
73 | let chars = "abcd"; | ||
74 | match t { | ||
75 | '\r' <|>if chars.clone().next() == Some('\n') => false, | ||
76 | _ => true | ||
77 | } | ||
78 | } | ||
79 | "#, | ||
80 | r#" | ||
81 | fn f() { | ||
82 | let t = 'a'; | ||
83 | let chars = "abcd"; | ||
84 | match t { | ||
85 | '\r' => if chars.clone().next() == Some('\n') { <|>false }, | ||
86 | _ => true | ||
87 | } | ||
88 | } | ||
89 | "#, | ||
90 | ); | ||
91 | } | ||
92 | |||
93 | #[test] | ||
94 | fn move_guard_to_arm_body_works_complex_match() { | ||
95 | check_assist( | ||
96 | move_guard_to_arm_body, | ||
97 | r#" | ||
98 | fn f() { | ||
99 | match x { | ||
100 | <|>y @ 4 | y @ 5 if y > 5 => true, | ||
101 | _ => false | ||
102 | } | ||
103 | } | ||
104 | "#, | ||
105 | r#" | ||
106 | fn f() { | ||
107 | match x { | ||
108 | y @ 4 | y @ 5 => if y > 5 { <|>true }, | ||
109 | _ => false | ||
110 | } | ||
111 | } | ||
112 | "#, | ||
113 | ); | ||
114 | } | ||
115 | } | ||
diff --git a/docs/user/features.md b/docs/user/features.md index cbfc491b2..a714574fb 100644 --- a/docs/user/features.md +++ b/docs/user/features.md | |||
@@ -388,6 +388,24 @@ fn foo() { | |||
388 | } | 388 | } |
389 | ``` | 389 | ``` |
390 | 390 | ||
391 | - Move guard expression to match arm body | ||
392 | ```rust | ||
393 | //before: | ||
394 | fn f() { | ||
395 | match x { | ||
396 | <|>y @ 4 | y @ 5 if y > 5 => true, | ||
397 | _ => false | ||
398 | } | ||
399 | } | ||
400 | //after: | ||
401 | fn f() { | ||
402 | match x { | ||
403 | y @ 4 | y @ 5 => if y > 5 { <|>true }, | ||
404 | _ => false | ||
405 | } | ||
406 | } | ||
407 | ``` | ||
408 | |||
391 | ### Magic Completions | 409 | ### Magic Completions |
392 | 410 | ||
393 | In addition to usual reference completion, rust-analyzer provides some ✨magic✨ | 411 | In addition to usual reference completion, rust-analyzer provides some ✨magic✨ |