diff options
author | bors[bot] <26634292+bors[bot]@users.noreply.github.com> | 2020-07-03 13:44:09 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2020-07-03 13:44:09 +0100 |
commit | f51b0cfdd6c23dd57a0a11154179730171c0425d (patch) | |
tree | f856e6b751b23a20d68e9df5350ec39d5e8ee85b /crates/ra_assists/src/handlers/extract_variable.rs | |
parent | ef6a6d75d5dba2825e6b90e67e0b147a5f7158e1 (diff) | |
parent | 4c9347ecc3356748c52847a29d5e53a65778dc13 (diff) |
Merge #5116
5116: Categorize assists r=matklad a=kjeremy
Categorize assists so that editors can use them. Follows the LSP spec pretty close (and some things may need adjustments) but this populates the Refactor menu in vscode and pushes quickfixes through again.
This is a prerequisite to filtering out assists that the client doesn't care about.
Fixes #4147
Co-authored-by: Jeremy Kolb <[email protected]>
Co-authored-by: kjeremy <[email protected]>
Diffstat (limited to 'crates/ra_assists/src/handlers/extract_variable.rs')
-rw-r--r-- | crates/ra_assists/src/handlers/extract_variable.rs | 137 |
1 files changed, 71 insertions, 66 deletions
diff --git a/crates/ra_assists/src/handlers/extract_variable.rs b/crates/ra_assists/src/handlers/extract_variable.rs index c4150d2bb..481baf1a4 100644 --- a/crates/ra_assists/src/handlers/extract_variable.rs +++ b/crates/ra_assists/src/handlers/extract_variable.rs | |||
@@ -9,7 +9,7 @@ use ra_syntax::{ | |||
9 | use stdx::format_to; | 9 | use stdx::format_to; |
10 | use test_utils::mark; | 10 | use test_utils::mark; |
11 | 11 | ||
12 | use crate::{AssistContext, AssistId, Assists}; | 12 | use crate::{AssistContext, AssistId, AssistKind, Assists}; |
13 | 13 | ||
14 | // Assist: extract_variable | 14 | // Assist: extract_variable |
15 | // | 15 | // |
@@ -43,80 +43,85 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext) -> Option | |||
43 | return None; | 43 | return None; |
44 | } | 44 | } |
45 | let target = expr.syntax().text_range(); | 45 | let target = expr.syntax().text_range(); |
46 | acc.add(AssistId("extract_variable"), "Extract into variable", target, move |edit| { | 46 | acc.add( |
47 | let field_shorthand = match expr.syntax().parent().and_then(ast::RecordField::cast) { | 47 | AssistId("extract_variable", AssistKind::RefactorExtract), |
48 | Some(field) => field.name_ref(), | 48 | "Extract into variable", |
49 | None => None, | 49 | target, |
50 | }; | 50 | move |edit| { |
51 | 51 | let field_shorthand = match expr.syntax().parent().and_then(ast::RecordField::cast) { | |
52 | let mut buf = String::new(); | 52 | Some(field) => field.name_ref(), |
53 | 53 | None => None, | |
54 | let var_name = match &field_shorthand { | 54 | }; |
55 | Some(it) => it.to_string(), | 55 | |
56 | None => "var_name".to_string(), | 56 | let mut buf = String::new(); |
57 | }; | 57 | |
58 | let expr_range = match &field_shorthand { | 58 | let var_name = match &field_shorthand { |
59 | Some(it) => it.syntax().text_range().cover(expr.syntax().text_range()), | 59 | Some(it) => it.to_string(), |
60 | None => expr.syntax().text_range(), | 60 | None => "var_name".to_string(), |
61 | }; | 61 | }; |
62 | 62 | let expr_range = match &field_shorthand { | |
63 | if wrap_in_block { | 63 | Some(it) => it.syntax().text_range().cover(expr.syntax().text_range()), |
64 | format_to!(buf, "{{ let {} = ", var_name); | 64 | None => expr.syntax().text_range(), |
65 | } else { | 65 | }; |
66 | format_to!(buf, "let {} = ", var_name); | 66 | |
67 | }; | 67 | if wrap_in_block { |
68 | format_to!(buf, "{}", expr.syntax()); | 68 | format_to!(buf, "{{ let {} = ", var_name); |
69 | 69 | } else { | |
70 | let full_stmt = ast::ExprStmt::cast(anchor_stmt.clone()); | 70 | format_to!(buf, "let {} = ", var_name); |
71 | let is_full_stmt = if let Some(expr_stmt) = &full_stmt { | 71 | }; |
72 | Some(expr.syntax().clone()) == expr_stmt.expr().map(|e| e.syntax().clone()) | 72 | format_to!(buf, "{}", expr.syntax()); |
73 | } else { | 73 | |
74 | false | 74 | let full_stmt = ast::ExprStmt::cast(anchor_stmt.clone()); |
75 | }; | 75 | let is_full_stmt = if let Some(expr_stmt) = &full_stmt { |
76 | if is_full_stmt { | 76 | Some(expr.syntax().clone()) == expr_stmt.expr().map(|e| e.syntax().clone()) |
77 | mark::hit!(test_extract_var_expr_stmt); | 77 | } else { |
78 | if full_stmt.unwrap().semicolon_token().is_none() { | 78 | false |
79 | buf.push_str(";"); | 79 | }; |
80 | if is_full_stmt { | ||
81 | mark::hit!(test_extract_var_expr_stmt); | ||
82 | if full_stmt.unwrap().semicolon_token().is_none() { | ||
83 | buf.push_str(";"); | ||
84 | } | ||
85 | match ctx.config.snippet_cap { | ||
86 | Some(cap) => { | ||
87 | let snip = buf | ||
88 | .replace(&format!("let {}", var_name), &format!("let $0{}", var_name)); | ||
89 | edit.replace_snippet(cap, expr_range, snip) | ||
90 | } | ||
91 | None => edit.replace(expr_range, buf), | ||
92 | } | ||
93 | return; | ||
94 | } | ||
95 | |||
96 | buf.push_str(";"); | ||
97 | |||
98 | // We want to maintain the indent level, | ||
99 | // but we do not want to duplicate possible | ||
100 | // extra newlines in the indent block | ||
101 | let text = indent.text(); | ||
102 | if text.starts_with('\n') { | ||
103 | buf.push_str("\n"); | ||
104 | buf.push_str(text.trim_start_matches('\n')); | ||
105 | } else { | ||
106 | buf.push_str(text); | ||
80 | } | 107 | } |
108 | |||
109 | edit.replace(expr_range, var_name.clone()); | ||
110 | let offset = anchor_stmt.text_range().start(); | ||
81 | match ctx.config.snippet_cap { | 111 | match ctx.config.snippet_cap { |
82 | Some(cap) => { | 112 | Some(cap) => { |
83 | let snip = | 113 | let snip = |
84 | buf.replace(&format!("let {}", var_name), &format!("let $0{}", var_name)); | 114 | buf.replace(&format!("let {}", var_name), &format!("let $0{}", var_name)); |
85 | edit.replace_snippet(cap, expr_range, snip) | 115 | edit.insert_snippet(cap, offset, snip) |
86 | } | 116 | } |
87 | None => edit.replace(expr_range, buf), | 117 | None => edit.insert(offset, buf), |
88 | } | 118 | } |
89 | return; | ||
90 | } | ||
91 | 119 | ||
92 | buf.push_str(";"); | 120 | if wrap_in_block { |
93 | 121 | edit.insert(anchor_stmt.text_range().end(), " }"); | |
94 | // We want to maintain the indent level, | ||
95 | // but we do not want to duplicate possible | ||
96 | // extra newlines in the indent block | ||
97 | let text = indent.text(); | ||
98 | if text.starts_with('\n') { | ||
99 | buf.push_str("\n"); | ||
100 | buf.push_str(text.trim_start_matches('\n')); | ||
101 | } else { | ||
102 | buf.push_str(text); | ||
103 | } | ||
104 | |||
105 | edit.replace(expr_range, var_name.clone()); | ||
106 | let offset = anchor_stmt.text_range().start(); | ||
107 | match ctx.config.snippet_cap { | ||
108 | Some(cap) => { | ||
109 | let snip = | ||
110 | buf.replace(&format!("let {}", var_name), &format!("let $0{}", var_name)); | ||
111 | edit.insert_snippet(cap, offset, snip) | ||
112 | } | 122 | } |
113 | None => edit.insert(offset, buf), | 123 | }, |
114 | } | 124 | ) |
115 | |||
116 | if wrap_in_block { | ||
117 | edit.insert(anchor_stmt.text_range().end(), " }"); | ||
118 | } | ||
119 | }) | ||
120 | } | 125 | } |
121 | 126 | ||
122 | /// Check whether the node is a valid expression which can be extracted to a variable. | 127 | /// Check whether the node is a valid expression which can be extracted to a variable. |