aboutsummaryrefslogtreecommitdiff
path: root/crates/libeditor
diff options
context:
space:
mode:
Diffstat (limited to 'crates/libeditor')
-rw-r--r--crates/libeditor/src/code_actions.rs48
-rw-r--r--crates/libeditor/src/lib.rs1
-rw-r--r--crates/libeditor/src/test_utils.rs19
3 files changed, 64 insertions, 4 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}
diff --git a/crates/libeditor/src/lib.rs b/crates/libeditor/src/lib.rs
index 4700ef328..b3cf2ef55 100644
--- a/crates/libeditor/src/lib.rs
+++ b/crates/libeditor/src/lib.rs
@@ -32,6 +32,7 @@ pub use self::{
32 code_actions::{ 32 code_actions::{
33 LocalEdit, 33 LocalEdit,
34 flip_comma, add_derive, add_impl, 34 flip_comma, add_derive, add_impl,
35 introduce_variable,
35 }, 36 },
36 typing::{join_lines, on_eq_typed}, 37 typing::{join_lines, on_eq_typed},
37 completion::{scope_completion, CompletionItem}, 38 completion::{scope_completion, CompletionItem},
diff --git a/crates/libeditor/src/test_utils.rs b/crates/libeditor/src/test_utils.rs
index 037319cd0..9c1279991 100644
--- a/crates/libeditor/src/test_utils.rs
+++ b/crates/libeditor/src/test_utils.rs
@@ -1,4 +1,4 @@
1use libsyntax2::{File, TextUnit}; 1use libsyntax2::{File, TextUnit, TextRange};
2pub use _test_utils::*; 2pub use _test_utils::*;
3use LocalEdit; 3use LocalEdit;
4 4
@@ -18,3 +18,20 @@ pub fn check_action<F: Fn(&File, TextUnit) -> Option<LocalEdit>> (
18 let actual = add_cursor(&actual, actual_cursor_pos); 18 let actual = add_cursor(&actual, actual_cursor_pos);
19 assert_eq_text!(after, &actual); 19 assert_eq_text!(after, &actual);
20} 20}
21
22pub fn check_action_range<F: Fn(&File, TextRange) -> Option<LocalEdit>> (
23 before: &str,
24 after: &str,
25 f: F,
26) {
27 let (range, before) = extract_range(before);
28 let file = File::parse(&before);
29 let result = f(&file, range).expect("code action is not applicable");
30 let actual = result.edit.apply(&before);
31 let actual_cursor_pos = match result.cursor_position {
32 None => result.edit.apply_to_offset(range.start()).unwrap(),
33 Some(off) => off,
34 };
35 let actual = add_cursor(&actual, actual_cursor_pos);
36 assert_eq_text!(after, &actual);
37}