// Assist: extract_function
//
-// Extracts selected statements into new function.
+// Extracts selected statements and comments into new function.
//
// ```
// fn main() {
// let n = 1;
// $0let m = n + 2;
+// // calculate
// let k = m + n;$0
// let g = 3;
// }
//
// fn $0fun_name(n: i32) {
// let m = n + 2;
+// // calculate
// let k = m + n;
// }
// ```
let full_body = parent.syntax().children_with_tokens();
let mut text_range = full_body
- .map(|stmt| stmt.text_range())
- .filter(|&stmt| selected.intersect(stmt).filter(|it| !it.is_empty()).is_some())
+ .filter(|it| ast::Stmt::can_cast(it.kind()) || it.kind() == COMMENT)
+ .map(|element| element.text_range())
+ .filter(|&range| selected.intersect(range).filter(|it| !it.is_empty()).is_some())
.reduce(|acc, stmt| acc.cover(stmt));
if let Some(tail_range) = parent
let stmt = make::expr_stmt(action);
let block = make::block_expr(iter::once(stmt.into()), None);
let controlflow_break_path = make::path_from_text("ControlFlow::Break");
- let condition = make::condition(
+ let condition = make::expr_let(
+ make::tuple_struct_pat(
+ controlflow_break_path,
+ iter::once(make::wildcard_pat().into()),
+ )
+ .into(),
call_expr,
- Some(
- make::tuple_struct_pat(
- controlflow_break_path,
- iter::once(make::wildcard_pat().into()),
- )
- .into(),
- ),
);
- make::expr_if(condition, block, None)
+ make::expr_if(condition.into(), block, None)
}
FlowHandler::IfOption { action } => {
let path = make::ext::ident_path("Some");
let value_pat = make::ext::simple_ident_pat(make::name("value"));
let pattern = make::tuple_struct_pat(path, iter::once(value_pat.into()));
- let cond = make::condition(call_expr, Some(pattern.into()));
+ let cond = make::expr_let(pattern.into(), call_expr);
let value = make::expr_path(make::ext::ident_path("value"));
let action_expr = action.make_result_handler(Some(value));
let action_stmt = make::expr_stmt(action_expr);
let then = make::block_expr(iter::once(action_stmt.into()), None);
- make::expr_if(cond, then, None)
+ make::expr_if(cond.into(), then, None)
}
FlowHandler::MatchOption { none } => {
let some_name = "value";
syntax::NodeOrToken::Node(n) => syntax::NodeOrToken::Node(
rewrite_body_segment(ctx, &fun.params, &handler, &n),
),
- syntax::NodeOrToken::Token(_) => it,
+ _ => it,
})
.collect();
let mut tail_expr = match &elements.last() {
- Some(element) => match element {
- syntax::NodeOrToken::Node(node) if ast::Expr::can_cast(node.kind()) => {
- ast::Expr::cast(node.clone())
- }
- _ => None,
- },
- None => None,
+ Some(syntax::NodeOrToken::Node(node)) if ast::Expr::can_cast(node.kind()) => {
+ ast::Expr::cast(node.clone())
+ }
+ _ => None,
};
match tail_expr {
};
let body_indent = IndentLevel(1);
- let elements: Vec<SyntaxElement> = elements
+ let elements = elements
.into_iter()
.map(|node_or_token| match &node_or_token {
syntax::NodeOrToken::Node(node) => match ast::Stmt::cast(node.clone()) {
let ast_node = indented.syntax().clone_subtree();
syntax::NodeOrToken::Node(ast_node)
}
- None => node_or_token,
+ _ => node_or_token,
},
_ => node_or_token,
})
);
}
+ #[test]
+ fn extract_does_not_tear_body_apart() {
+ check_assist(
+ extract_function,
+ r#"
+fn foo() {
+ $0foo();
+}$0
+"#,
+ r#"
+fn foo() {
+ fun_name();
+}
+
+fn $0fun_name() {
+ foo();
+}
+"#,
+ );
+ }
+
#[test]
fn extract_does_not_wrap_res_in_res() {
check_assist(
extract_function,
r#"
fn func() {
- let i = 0;
- $0
+ let i = 0;$0
let a = 0;
// comment here!
let x = 0;$0
r#"
fn func() {
let i = 0;
-
fun_name();
}
);
}
+ // FIXME: we do want to preserve whitespace
#[test]
fn extract_function_does_not_preserve_whitespace() {
check_assist(