@@ -13,7 +13,7 @@ use syntax::{
13
13
edit:: { AstNodeEdit , IndentLevel } ,
14
14
AstNode ,
15
15
} ,
16
- Direction , SyntaxElement ,
16
+ AstToken , Direction , SyntaxElement ,
17
17
SyntaxKind :: { self , BLOCK_EXPR , BREAK_EXPR , COMMENT , PATH_EXPR , RETURN_EXPR } ,
18
18
SyntaxNode , SyntaxToken , TextRange , TextSize , TokenAtOffset , T ,
19
19
} ;
@@ -105,9 +105,10 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext) -> Option
105
105
106
106
builder. replace ( target_range, format_replacement ( ctx, & fun) ) ;
107
107
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 ( ) ;
109
110
110
- let fn_def = format_function ( ctx, module, & fun, indent ) ;
111
+ let fn_def = format_function ( ctx, module, & fun, old_indent , new_indent ) ;
111
112
let insert_offset = insert_after. text_range ( ) . end ( ) ;
112
113
builder. insert ( insert_offset, fn_def) ;
113
114
} ,
@@ -260,6 +261,18 @@ impl FunctionBody {
260
261
Some ( FunctionBody :: Span { elements, leading_indent } )
261
262
}
262
263
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
+
263
276
fn tail_expr ( & self ) -> Option < ast:: Expr > {
264
277
match & self {
265
278
FunctionBody :: Expr ( expr) => Some ( expr. clone ( ) ) ,
@@ -747,16 +760,17 @@ fn format_function(
747
760
ctx : & AssistContext ,
748
761
module : hir:: Module ,
749
762
fun : & Function ,
750
- indent : IndentLevel ,
763
+ old_indent : IndentLevel ,
764
+ new_indent : IndentLevel ,
751
765
) -> String {
752
766
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) ;
754
768
format_function_param_list_to ( & mut fn_def, ctx, module, fun) ;
755
769
fn_def. push ( ')' ) ;
756
770
format_function_ret_to ( & mut fn_def, ctx, module, fun) ;
757
771
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 ) ;
760
774
761
775
fn_def
762
776
}
@@ -818,20 +832,32 @@ fn format_function_ret_to(
818
832
fn format_function_body_to (
819
833
fn_def : & mut String ,
820
834
ctx : & AssistContext ,
821
- indent : IndentLevel ,
835
+ old_indent : IndentLevel ,
836
+ new_indent : IndentLevel ,
822
837
fun : & Function ,
823
838
) {
824
839
match & fun. body {
825
840
FunctionBody :: Expr ( expr) => {
826
841
fn_def. push ( '\n' ) ;
827
- let expr = expr. indent ( indent) ;
842
+ let expr = expr. dedent ( old_indent ) . indent ( new_indent + 1 ) ;
828
843
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) ;
830
845
fn_def. push ( '\n' ) ;
831
846
}
832
847
FunctionBody :: Span { elements, leading_indent } => {
833
848
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
+
835
861
match element {
836
862
syntax:: NodeOrToken :: Node ( node) => {
837
863
format_to ! ( fn_def, "{}" , fix_param_usages( ctx, & fun. params, node) ) ;
@@ -849,9 +875,9 @@ fn format_function_body_to(
849
875
850
876
match fun. vars_defined_in_body_and_outlive . as_slice ( ) {
851
877
[ ] => { }
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( ) ) ,
853
879
[ 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( ) ) ;
855
881
for var in vs {
856
882
format_to ! ( fn_def, ", {}" , var. name( ctx. db( ) ) . unwrap( ) ) ;
857
883
}
@@ -2065,6 +2091,68 @@ fn foo() {
2065
2091
2066
2092
fn $0fun_name(c: &Counter) {
2067
2093
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
+ }
2068
2156
}" ,
2069
2157
) ;
2070
2158
}
0 commit comments