aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src/handlers/extract_variable.rs
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-07-03 13:44:09 +0100
committerGitHub <[email protected]>2020-07-03 13:44:09 +0100
commitf51b0cfdd6c23dd57a0a11154179730171c0425d (patch)
treef856e6b751b23a20d68e9df5350ec39d5e8ee85b /crates/ra_assists/src/handlers/extract_variable.rs
parentef6a6d75d5dba2825e6b90e67e0b147a5f7158e1 (diff)
parent4c9347ecc3356748c52847a29d5e53a65778dc13 (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.rs137
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::{
9use stdx::format_to; 9use stdx::format_to;
10use test_utils::mark; 10use test_utils::mark;
11 11
12use crate::{AssistContext, AssistId, Assists}; 12use 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.