aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_editor/src/assists/introduce_variable.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_editor/src/assists/introduce_variable.rs')
-rw-r--r--crates/ra_editor/src/assists/introduce_variable.rs84
1 files changed, 36 insertions, 48 deletions
diff --git a/crates/ra_editor/src/assists/introduce_variable.rs b/crates/ra_editor/src/assists/introduce_variable.rs
index 17ab521fa..782861023 100644
--- a/crates/ra_editor/src/assists/introduce_variable.rs
+++ b/crates/ra_editor/src/assists/introduce_variable.rs
@@ -1,19 +1,13 @@
1use ra_text_edit::TextEditBuilder;
2use ra_syntax::{ 1use ra_syntax::{
3 algo::{find_covering_node},
4 ast::{self, AstNode}, 2 ast::{self, AstNode},
5 SourceFileNode, 3 SyntaxKind::WHITESPACE,
6 SyntaxKind::{WHITESPACE}, 4 SyntaxNodeRef, TextUnit,
7 SyntaxNodeRef, TextRange, TextUnit,
8}; 5};
9 6
10use crate::assists::LocalEdit; 7use crate::assists::{AssistCtx, Assist};
11 8
12pub fn introduce_variable<'a>( 9pub fn introduce_variable<'a>(ctx: AssistCtx) -> Option<Assist> {
13 file: &'a SourceFileNode, 10 let node = ctx.covering_node();
14 range: TextRange,
15) -> Option<impl FnOnce() -> LocalEdit + 'a> {
16 let node = find_covering_node(file.syntax(), range);
17 let expr = node.ancestors().filter_map(ast::Expr::cast).next()?; 11 let expr = node.ancestors().filter_map(ast::Expr::cast).next()?;
18 12
19 let anchor_stmt = anchor_stmt(expr)?; 13 let anchor_stmt = anchor_stmt(expr)?;
@@ -21,9 +15,8 @@ pub fn introduce_variable<'a>(
21 if indent.kind() != WHITESPACE { 15 if indent.kind() != WHITESPACE {
22 return None; 16 return None;
23 } 17 }
24 return Some(move || { 18 ctx.build("introduce variable", move |edit| {
25 let mut buf = String::new(); 19 let mut buf = String::new();
26 let mut edit = TextEditBuilder::new();
27 20
28 buf.push_str("let var_name = "); 21 buf.push_str("let var_name = ");
29 expr.syntax().text().push_to(&mut buf); 22 expr.syntax().text().push_to(&mut buf);
@@ -40,43 +33,39 @@ pub fn introduce_variable<'a>(
40 edit.replace(expr.syntax().range(), "var_name".to_string()); 33 edit.replace(expr.syntax().range(), "var_name".to_string());
41 edit.insert(anchor_stmt.range().start(), buf); 34 edit.insert(anchor_stmt.range().start(), buf);
42 } 35 }
43 let cursor_position = anchor_stmt.range().start() + TextUnit::of_str("let "); 36 edit.set_cursor(anchor_stmt.range().start() + TextUnit::of_str("let "));
44 LocalEdit { 37 })
45 label: "introduce variable".to_string(), 38}
46 edit: edit.finish(),
47 cursor_position: Some(cursor_position),
48 }
49 });
50 39
51 /// Statement or last in the block expression, which will follow 40/// Statement or last in the block expression, which will follow
52 /// the freshly introduced var. 41/// the freshly introduced var.
53 fn anchor_stmt(expr: ast::Expr) -> Option<SyntaxNodeRef> { 42fn anchor_stmt(expr: ast::Expr) -> Option<SyntaxNodeRef> {
54 expr.syntax().ancestors().find(|&node| { 43 expr.syntax().ancestors().find(|&node| {
55 if ast::Stmt::cast(node).is_some() { 44 if ast::Stmt::cast(node).is_some() {
45 return true;
46 }
47 if let Some(expr) = node
48 .parent()
49 .and_then(ast::Block::cast)
50 .and_then(|it| it.expr())
51 {
52 if expr.syntax() == node {
56 return true; 53 return true;
57 } 54 }
58 if let Some(expr) = node 55 }
59 .parent() 56 false
60 .and_then(ast::Block::cast) 57 })
61 .and_then(|it| it.expr())
62 {
63 if expr.syntax() == node {
64 return true;
65 }
66 }
67 false
68 })
69 }
70} 58}
71 59
72#[cfg(test)] 60#[cfg(test)]
73mod tests { 61mod tests {
74 use super::*; 62 use super::*;
75 use crate::test_utils::check_action_range; 63 use crate::assists::check_assist_range;
76 64
77 #[test] 65 #[test]
78 fn test_introduce_var_simple() { 66 fn test_introduce_var_simple() {
79 check_action_range( 67 check_assist_range(
68 introduce_variable,
80 " 69 "
81fn foo() { 70fn foo() {
82 foo(<|>1 + 1<|>); 71 foo(<|>1 + 1<|>);
@@ -86,13 +75,13 @@ fn foo() {
86 let <|>var_name = 1 + 1; 75 let <|>var_name = 1 + 1;
87 foo(var_name); 76 foo(var_name);
88}", 77}",
89 |file, range| introduce_variable(file, range).map(|f| f()),
90 ); 78 );
91 } 79 }
92 80
93 #[test] 81 #[test]
94 fn test_introduce_var_expr_stmt() { 82 fn test_introduce_var_expr_stmt() {
95 check_action_range( 83 check_assist_range(
84 introduce_variable,
96 " 85 "
97fn foo() { 86fn foo() {
98 <|>1 + 1<|>; 87 <|>1 + 1<|>;
@@ -101,13 +90,13 @@ fn foo() {
101fn foo() { 90fn foo() {
102 let <|>var_name = 1 + 1; 91 let <|>var_name = 1 + 1;
103}", 92}",
104 |file, range| introduce_variable(file, range).map(|f| f()),
105 ); 93 );
106 } 94 }
107 95
108 #[test] 96 #[test]
109 fn test_introduce_var_part_of_expr_stmt() { 97 fn test_introduce_var_part_of_expr_stmt() {
110 check_action_range( 98 check_assist_range(
99 introduce_variable,
111 " 100 "
112fn foo() { 101fn foo() {
113 <|>1<|> + 1; 102 <|>1<|> + 1;
@@ -117,13 +106,13 @@ fn foo() {
117 let <|>var_name = 1; 106 let <|>var_name = 1;
118 var_name + 1; 107 var_name + 1;
119}", 108}",
120 |file, range| introduce_variable(file, range).map(|f| f()),
121 ); 109 );
122 } 110 }
123 111
124 #[test] 112 #[test]
125 fn test_introduce_var_last_expr() { 113 fn test_introduce_var_last_expr() {
126 check_action_range( 114 check_assist_range(
115 introduce_variable,
127 " 116 "
128fn foo() { 117fn foo() {
129 bar(<|>1 + 1<|>) 118 bar(<|>1 + 1<|>)
@@ -133,13 +122,13 @@ fn foo() {
133 let <|>var_name = 1 + 1; 122 let <|>var_name = 1 + 1;
134 bar(var_name) 123 bar(var_name)
135}", 124}",
136 |file, range| introduce_variable(file, range).map(|f| f()),
137 ); 125 );
138 } 126 }
139 127
140 #[test] 128 #[test]
141 fn test_introduce_var_last_full_expr() { 129 fn test_introduce_var_last_full_expr() {
142 check_action_range( 130 check_assist_range(
131 introduce_variable,
143 " 132 "
144fn foo() { 133fn foo() {
145 <|>bar(1 + 1)<|> 134 <|>bar(1 + 1)<|>
@@ -149,7 +138,6 @@ fn foo() {
149 let <|>var_name = bar(1 + 1); 138 let <|>var_name = bar(1 + 1);
150 var_name 139 var_name
151}", 140}",
152 |file, range| introduce_variable(file, range).map(|f| f()),
153 ); 141 );
154 } 142 }
155 143