@@ -13,7 +13,7 @@ use syntax::{
1313 edit:: { AstNodeEdit , IndentLevel } ,
1414 AstNode ,
1515 } ,
16- Direction , SyntaxElement ,
16+ AstToken , Direction , SyntaxElement ,
1717 SyntaxKind :: { self , BLOCK_EXPR , BREAK_EXPR , COMMENT , PATH_EXPR , RETURN_EXPR } ,
1818 SyntaxNode , SyntaxToken , TextRange , TextSize , TokenAtOffset , T ,
1919} ;
@@ -105,9 +105,10 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext) -> Option
105105
106106 builder. replace ( target_range, format_replacement ( ctx, & fun) ) ;
107107
108- let indent = IndentLevel :: from_node ( & insert_after) ;
108+ let new_indent = IndentLevel :: from_node ( & insert_after) ;
109+ let old_indent = fun. body . indent_level ( ) ;
109110
110- let fn_def = format_function ( ctx, module, & fun, indent ) ;
111+ let fn_def = format_function ( ctx, module, & fun, old_indent , new_indent ) ;
111112 let insert_offset = insert_after. text_range ( ) . end ( ) ;
112113 builder. insert ( insert_offset, fn_def) ;
113114 } ,
@@ -260,6 +261,18 @@ impl FunctionBody {
260261 Some ( FunctionBody :: Span { elements, leading_indent } )
261262 }
262263
264+ fn indent_level ( & self ) -> IndentLevel {
265+ match & self {
266+ FunctionBody :: Expr ( expr) => IndentLevel :: from_node ( expr. syntax ( ) ) ,
267+ FunctionBody :: Span { elements, .. } => elements
268+ . iter ( )
269+ . filter_map ( SyntaxElement :: as_node)
270+ . map ( IndentLevel :: from_node)
271+ . min_by_key ( |level| level. 0 )
272+ . expect ( "body must contain at least one node" ) ,
273+ }
274+ }
275+
263276 fn tail_expr ( & self ) -> Option < ast:: Expr > {
264277 match & self {
265278 FunctionBody :: Expr ( expr) => Some ( expr. clone ( ) ) ,
@@ -747,16 +760,17 @@ fn format_function(
747760 ctx : & AssistContext ,
748761 module : hir:: Module ,
749762 fun : & Function ,
750- indent : IndentLevel ,
763+ old_indent : IndentLevel ,
764+ new_indent : IndentLevel ,
751765) -> String {
752766 let mut fn_def = String :: new ( ) ;
753- format_to ! ( fn_def, "\n \n {}fn $0{}(" , indent , fun. name) ;
767+ format_to ! ( fn_def, "\n \n {}fn $0{}(" , new_indent , fun. name) ;
754768 format_function_param_list_to ( & mut fn_def, ctx, module, fun) ;
755769 fn_def. push ( ')' ) ;
756770 format_function_ret_to ( & mut fn_def, ctx, module, fun) ;
757771 fn_def. push_str ( " {" ) ;
758- format_function_body_to ( & mut fn_def, ctx, indent , fun) ;
759- format_to ! ( fn_def, "{}}}" , indent ) ;
772+ format_function_body_to ( & mut fn_def, ctx, old_indent , new_indent , fun) ;
773+ format_to ! ( fn_def, "{}}}" , new_indent ) ;
760774
761775 fn_def
762776}
@@ -818,20 +832,32 @@ fn format_function_ret_to(
818832fn format_function_body_to (
819833 fn_def : & mut String ,
820834 ctx : & AssistContext ,
821- indent : IndentLevel ,
835+ old_indent : IndentLevel ,
836+ new_indent : IndentLevel ,
822837 fun : & Function ,
823838) {
824839 match & fun. body {
825840 FunctionBody :: Expr ( expr) => {
826841 fn_def. push ( '\n' ) ;
827- let expr = expr. indent ( indent) ;
842+ let expr = expr. dedent ( old_indent ) . indent ( new_indent + 1 ) ;
828843 let expr = fix_param_usages ( ctx, & fun. params , expr. syntax ( ) ) ;
829- format_to ! ( fn_def, "{}{}" , indent + 1 , expr) ;
844+ format_to ! ( fn_def, "{}{}" , new_indent + 1 , expr) ;
830845 fn_def. push ( '\n' ) ;
831846 }
832847 FunctionBody :: Span { elements, leading_indent } => {
833848 format_to ! ( fn_def, "{}" , leading_indent) ;
834- for element in elements {
849+ let new_indent_str = format ! ( "\n {}" , new_indent + 1 ) ;
850+ for mut element in elements {
851+ let new_ws;
852+ if let Some ( ws) = element. as_token ( ) . cloned ( ) . and_then ( ast:: Whitespace :: cast) {
853+ let text = ws. syntax ( ) . text ( ) ;
854+ if text. contains ( '\n' ) {
855+ let new_text = text. replace ( & format ! ( "\n {}" , old_indent) , & new_indent_str) ;
856+ new_ws = ast:: make:: tokens:: whitespace ( & new_text) . into ( ) ;
857+ element = & new_ws;
858+ }
859+ }
860+
835861 match element {
836862 syntax:: NodeOrToken :: Node ( node) => {
837863 format_to ! ( fn_def, "{}" , fix_param_usages( ctx, & fun. params, node) ) ;
@@ -849,9 +875,9 @@ fn format_function_body_to(
849875
850876 match fun. vars_defined_in_body_and_outlive . as_slice ( ) {
851877 [ ] => { }
852- [ var] => format_to ! ( fn_def, "{}{}\n " , indent + 1 , var. name( ctx. db( ) ) . unwrap( ) ) ,
878+ [ var] => format_to ! ( fn_def, "{}{}\n " , new_indent + 1 , var. name( ctx. db( ) ) . unwrap( ) ) ,
853879 [ v0, vs @ ..] => {
854- format_to ! ( fn_def, "{}({}" , indent + 1 , v0. name( ctx. db( ) ) . unwrap( ) ) ;
880+ format_to ! ( fn_def, "{}({}" , new_indent + 1 , v0. name( ctx. db( ) ) . unwrap( ) ) ;
855881 for var in vs {
856882 format_to ! ( fn_def, ", {}" , var. name( ctx. db( ) ) . unwrap( ) ) ;
857883 }
@@ -2065,6 +2091,68 @@ fn foo() {
20652091
20662092fn $0fun_name(c: &Counter) {
20672093 let n = c.0;
2094+ }" ,
2095+ ) ;
2096+ }
2097+
2098+ #[ test]
2099+ fn indented_stmts ( ) {
2100+ check_assist (
2101+ extract_function,
2102+ r"
2103+ fn foo() {
2104+ if true {
2105+ loop {
2106+ $0let n = 1;
2107+ let m = 2;$0
2108+ }
2109+ }
2110+ }" ,
2111+ r"
2112+ fn foo() {
2113+ if true {
2114+ loop {
2115+ fun_name();
2116+ }
2117+ }
2118+ }
2119+
2120+ fn $0fun_name() {
2121+ let n = 1;
2122+ let m = 2;
2123+ }" ,
2124+ ) ;
2125+ }
2126+
2127+ #[ test]
2128+ fn indented_stmts_inside_mod ( ) {
2129+ check_assist (
2130+ extract_function,
2131+ r"
2132+ mod bar {
2133+ fn foo() {
2134+ if true {
2135+ loop {
2136+ $0let n = 1;
2137+ let m = 2;$0
2138+ }
2139+ }
2140+ }
2141+ }" ,
2142+ r"
2143+ mod bar {
2144+ fn foo() {
2145+ if true {
2146+ loop {
2147+ fun_name();
2148+ }
2149+ }
2150+ }
2151+
2152+ fn $0fun_name() {
2153+ let n = 1;
2154+ let m = 2;
2155+ }
20682156}" ,
20692157 ) ;
20702158 }
0 commit comments