aboutsummaryrefslogtreecommitdiff
path: root/crates/libeditor/src/code_actions.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/libeditor/src/code_actions.rs')
-rw-r--r--crates/libeditor/src/code_actions.rs48
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 @@
1use join_to_string::join; 1use join_to_string::join;
2 2
3use libsyntax2::{ 3use 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
102pub 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
100fn non_trivia_sibling(node: SyntaxNodeRef, direction: Direction) -> Option<SyntaxNodeRef> { 127fn 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)]
107mod tests { 134mod 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 "
189fn foo() {
190 foo(<|>1 + 1<|>);
191}", "
192fn 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}