aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_editor/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_editor/src')
-rw-r--r--crates/ra_editor/src/code_actions.rs56
1 files changed, 45 insertions, 11 deletions
diff --git a/crates/ra_editor/src/code_actions.rs b/crates/ra_editor/src/code_actions.rs
index cadcd2720..ef6df0d53 100644
--- a/crates/ra_editor/src/code_actions.rs
+++ b/crates/ra_editor/src/code_actions.rs
@@ -103,35 +103,52 @@ pub fn introduce_variable<'a>(
103) -> Option<impl FnOnce() -> LocalEdit + 'a> { 103) -> Option<impl FnOnce() -> LocalEdit + 'a> {
104 let node = find_covering_node(file.syntax(), range); 104 let node = find_covering_node(file.syntax(), range);
105 let expr = node.ancestors().filter_map(ast::Expr::cast).next()?; 105 let expr = node.ancestors().filter_map(ast::Expr::cast).next()?;
106 let anchor_stmt = expr 106
107 .syntax() 107 let anchor_stmt = ahchor_stmt(expr)?;
108 .ancestors() 108 let indent = anchor_stmt.prev_sibling()?;
109 .filter_map(ast::Stmt::cast)
110 .next()?;
111 let indent = anchor_stmt.syntax().prev_sibling()?;
112 if indent.kind() != WHITESPACE { 109 if indent.kind() != WHITESPACE {
113 return None; 110 return None;
114 } 111 }
115 Some(move || { 112 return Some(move || {
116 let mut buf = String::new(); 113 let mut buf = String::new();
117 let mut edit = EditBuilder::new(); 114 let mut edit = EditBuilder::new();
118 115
119 buf.push_str("let var_name = "); 116 buf.push_str("let var_name = ");
120 expr.syntax().text().push_to(&mut buf); 117 expr.syntax().text().push_to(&mut buf);
121 if expr.syntax().range().start() == anchor_stmt.syntax().range().start() { 118 if expr.syntax().range().start() == anchor_stmt.range().start() {
122 edit.replace(expr.syntax().range(), buf); 119 edit.replace(expr.syntax().range(), buf);
123 } else { 120 } else {
124 buf.push_str(";"); 121 buf.push_str(";");
125 indent.text().push_to(&mut buf); 122 indent.text().push_to(&mut buf);
126 edit.replace(expr.syntax().range(), "var_name".to_string()); 123 edit.replace(expr.syntax().range(), "var_name".to_string());
127 edit.insert(anchor_stmt.syntax().range().start(), buf); 124 edit.insert(anchor_stmt.range().start(), buf);
128 } 125 }
129 let cursor_position = anchor_stmt.syntax().range().start() + TextUnit::of_str("let "); 126 let cursor_position = anchor_stmt.range().start() + TextUnit::of_str("let ");
130 LocalEdit { 127 LocalEdit {
131 edit: edit.finish(), 128 edit: edit.finish(),
132 cursor_position: Some(cursor_position), 129 cursor_position: Some(cursor_position),
133 } 130 }
134 }) 131 });
132
133 /// Statement or last in the block expression, which will follow
134 /// the freshly introduced var.
135 fn ahchor_stmt(expr: ast::Expr) -> Option<SyntaxNodeRef> {
136 expr.syntax().ancestors().find(|&node| {
137 if ast::Stmt::cast(node).is_some() {
138 return true;
139 }
140 if let Some(expr) = node
141 .parent()
142 .and_then(ast::Block::cast)
143 .and_then(|it| it.expr())
144 {
145 if expr.syntax() == node {
146 return true;
147 }
148 }
149 false
150 })
151 }
135} 152}
136 153
137fn non_trivia_sibling(node: SyntaxNodeRef, direction: Direction) -> Option<SyntaxNodeRef> { 154fn non_trivia_sibling(node: SyntaxNodeRef, direction: Direction) -> Option<SyntaxNodeRef> {
@@ -207,6 +224,7 @@ fn foo() {
207 |file, range| introduce_variable(file, range).map(|f| f()), 224 |file, range| introduce_variable(file, range).map(|f| f()),
208 ); 225 );
209 } 226 }
227
210 #[test] 228 #[test]
211 fn test_intrdoduce_var_expr_stmt() { 229 fn test_intrdoduce_var_expr_stmt() {
212 check_action_range( 230 check_action_range(
@@ -222,4 +240,20 @@ fn foo() {
222 ); 240 );
223 } 241 }
224 242
243 #[test]
244 fn test_intrdoduce_var_last_expr() {
245 check_action_range(
246 "
247fn foo() {
248 bar(<|>1 + 1<|>)
249}",
250 "
251fn foo() {
252 let <|>var_name = 1 + 1;
253 bar(var_name)
254}",
255 |file, range| introduce_variable(file, range).map(|f| f()),
256 );
257 }
258
225} 259}