diff options
Diffstat (limited to 'crates/libeditor/src/code_actions.rs')
-rw-r--r-- | crates/libeditor/src/code_actions.rs | 48 |
1 files changed, 45 insertions, 3 deletions
diff --git a/crates/libeditor/src/code_actions.rs b/crates/libeditor/src/code_actions.rs index 522b605ed..ebe70681b 100644 --- a/crates/libeditor/src/code_actions.rs +++ b/crates/libeditor/src/code_actions.rs | |||
@@ -1,13 +1,15 @@ | |||
1 | use join_to_string::join; | 1 | use join_to_string::join; |
2 | 2 | ||
3 | use libsyntax2::{ | 3 | use libsyntax2::{ |
4 | File, TextUnit, | 4 | File, TextUnit, TextRange, |
5 | ast::{self, AstNode, AttrsOwner, TypeParamsOwner, NameOwner}, | 5 | ast::{self, AstNode, AttrsOwner, TypeParamsOwner, NameOwner}, |
6 | SyntaxKind::COMMA, | 6 | SyntaxKind::{COMMA, WHITESPACE}, |
7 | SyntaxNodeRef, | 7 | SyntaxNodeRef, |
8 | algo::{ | 8 | algo::{ |
9 | Direction, siblings, | 9 | Direction, siblings, |
10 | find_leaf_at_offset, | 10 | find_leaf_at_offset, |
11 | find_covering_node, | ||
12 | ancestors, | ||
11 | }, | 13 | }, |
12 | }; | 14 | }; |
13 | 15 | ||
@@ -97,6 +99,31 @@ pub fn add_impl<'a>(file: &'a File, offset: TextUnit) -> Option<impl FnOnce() -> | |||
97 | }) | 99 | }) |
98 | } | 100 | } |
99 | 101 | ||
102 | pub fn introduce_variable<'a>(file: &'a File, range: TextRange) -> Option<impl FnOnce() -> LocalEdit + 'a> { | ||
103 | let node = find_covering_node(file.syntax(), range); | ||
104 | let expr = ancestors(node).filter_map(ast::Expr::cast).next()?; | ||
105 | let anchor_stmt = ancestors(expr.syntax()).filter_map(ast::Stmt::cast).next()?; | ||
106 | let indent = anchor_stmt.syntax().prev_sibling()?; | ||
107 | if indent.kind() != WHITESPACE { | ||
108 | return None; | ||
109 | } | ||
110 | Some(move || { | ||
111 | let mut buf = String::new(); | ||
112 | buf.push_str("let var_name = "); | ||
113 | expr.syntax().text().push_to(&mut buf); | ||
114 | buf.push_str(";"); | ||
115 | indent.text().push_to(&mut buf); | ||
116 | |||
117 | let mut edit = EditBuilder::new(); | ||
118 | edit.replace(expr.syntax().range(), "var_name".to_string()); | ||
119 | edit.insert(anchor_stmt.syntax().range().start(), buf); | ||
120 | LocalEdit { | ||
121 | edit: edit.finish(), | ||
122 | cursor_position: Some(anchor_stmt.syntax().range().start() + TextUnit::of_str("let ")), | ||
123 | } | ||
124 | }) | ||
125 | } | ||
126 | |||
100 | fn non_trivia_sibling(node: SyntaxNodeRef, direction: Direction) -> Option<SyntaxNodeRef> { | 127 | fn non_trivia_sibling(node: SyntaxNodeRef, direction: Direction) -> Option<SyntaxNodeRef> { |
101 | siblings(node, direction) | 128 | siblings(node, direction) |
102 | .skip(1) | 129 | .skip(1) |
@@ -106,7 +133,7 @@ fn non_trivia_sibling(node: SyntaxNodeRef, direction: Direction) -> Option<Synta | |||
106 | #[cfg(test)] | 133 | #[cfg(test)] |
107 | mod tests { | 134 | mod tests { |
108 | use super::*; | 135 | use super::*; |
109 | use test_utils::check_action; | 136 | use test_utils::{check_action, check_action_range}; |
110 | 137 | ||
111 | #[test] | 138 | #[test] |
112 | fn test_swap_comma() { | 139 | fn test_swap_comma() { |
@@ -155,4 +182,19 @@ mod tests { | |||
155 | ); | 182 | ); |
156 | } | 183 | } |
157 | 184 | ||
185 | #[test] | ||
186 | fn test_intrdoduce_var() { | ||
187 | check_action_range( | ||
188 | " | ||
189 | fn foo() { | ||
190 | foo(<|>1 + 1<|>); | ||
191 | }", " | ||
192 | fn foo() { | ||
193 | let <|>var_name = 1 + 1; | ||
194 | foo(var_name); | ||
195 | }", | ||
196 | |file, range| introduce_variable(file, range).map(|f| f()), | ||
197 | ); | ||
198 | } | ||
199 | |||
158 | } | 200 | } |