Improve 'introduce variable'

- make it possible to extract a prefix of an expression statement (e.g.
   <|>foo.bar()<|>.baz())
 - don't turn the last expression in a block into a let statement
This commit is contained in:
Florian Diebold 2018-12-02 14:00:46 +01:00
parent 477de790b0
commit 2706456832
2 changed files with 44 additions and 7 deletions

View file

@ -113,7 +113,7 @@ pub fn introduce_variable<'a>(
let node = find_covering_node(file.syntax(), range); let node = find_covering_node(file.syntax(), range);
let expr = node.ancestors().filter_map(ast::Expr::cast).next()?; let expr = node.ancestors().filter_map(ast::Expr::cast).next()?;
let anchor_stmt = ahchor_stmt(expr)?; let anchor_stmt = anchor_stmt(expr)?;
let indent = anchor_stmt.prev_sibling()?; let indent = anchor_stmt.prev_sibling()?;
if indent.kind() != WHITESPACE { if indent.kind() != WHITESPACE {
return None; return None;
@ -124,7 +124,12 @@ pub fn introduce_variable<'a>(
buf.push_str("let var_name = "); buf.push_str("let var_name = ");
expr.syntax().text().push_to(&mut buf); expr.syntax().text().push_to(&mut buf);
if expr.syntax().range().start() == anchor_stmt.range().start() { let is_full_stmt = if let Some(expr_stmt) = ast::ExprStmt::cast(anchor_stmt) {
Some(expr.syntax()) == expr_stmt.expr().map(|e| e.syntax())
} else {
false
};
if is_full_stmt {
edit.replace(expr.syntax().range(), buf); edit.replace(expr.syntax().range(), buf);
} else { } else {
buf.push_str(";"); buf.push_str(";");
@ -141,7 +146,7 @@ pub fn introduce_variable<'a>(
/// Statement or last in the block expression, which will follow /// Statement or last in the block expression, which will follow
/// the freshly introduced var. /// the freshly introduced var.
fn ahchor_stmt(expr: ast::Expr) -> Option<SyntaxNodeRef> { fn anchor_stmt(expr: ast::Expr) -> Option<SyntaxNodeRef> {
expr.syntax().ancestors().find(|&node| { expr.syntax().ancestors().find(|&node| {
if ast::Stmt::cast(node).is_some() { if ast::Stmt::cast(node).is_some() {
return true; return true;
@ -219,7 +224,7 @@ mod tests {
} }
#[test] #[test]
fn test_intrdoduce_var_simple() { fn test_introduce_var_simple() {
check_action_range( check_action_range(
" "
fn foo() { fn foo() {
@ -235,7 +240,7 @@ fn foo() {
} }
#[test] #[test]
fn test_intrdoduce_var_expr_stmt() { fn test_introduce_var_expr_stmt() {
check_action_range( check_action_range(
" "
fn foo() { fn foo() {
@ -250,7 +255,23 @@ fn foo() {
} }
#[test] #[test]
fn test_intrdoduce_var_last_expr() { fn test_introduce_var_part_of_expr_stmt() {
check_action_range(
"
fn foo() {
<|>1<|> + 1;
}",
"
fn foo() {
let <|>var_name = 1;
var_name + 1;
}",
|file, range| introduce_variable(file, range).map(|f| f()),
);
}
#[test]
fn test_introduce_var_last_expr() {
check_action_range( check_action_range(
" "
fn foo() { fn foo() {
@ -265,4 +286,20 @@ fn foo() {
); );
} }
#[test]
fn test_introduce_var_last_full_expr() {
check_action_range(
"
fn foo() {
<|>bar(1 + 1)<|>
}",
"
fn foo() {
let <|>var_name = bar(1 + 1);
var_name
}",
|file, range| introduce_variable(file, range).map(|f| f()),
);
}
} }

View file

@ -26,7 +26,7 @@ impl EditBuilder {
} }
pub fn finish(self) -> Edit { pub fn finish(self) -> Edit {
let mut atoms = self.atoms; let mut atoms = self.atoms;
atoms.sort_by_key(|a| a.delete.start()); atoms.sort_by_key(|a| (a.delete.start(), a.delete.end()));
for (a1, a2) in atoms.iter().zip(atoms.iter().skip(1)) { for (a1, a2) in atoms.iter().zip(atoms.iter().skip(1)) {
assert!(a1.delete.end() <= a2.delete.start()) assert!(a1.delete.end() <= a2.delete.start())
} }