aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_assists/src/handlers/add_function.rs69
-rw-r--r--crates/ra_syntax/src/ast/make.rs4
2 files changed, 27 insertions, 46 deletions
diff --git a/crates/ra_assists/src/handlers/add_function.rs b/crates/ra_assists/src/handlers/add_function.rs
index 9bd46f5dc..f185cffdb 100644
--- a/crates/ra_assists/src/handlers/add_function.rs
+++ b/crates/ra_assists/src/handlers/add_function.rs
@@ -81,6 +81,7 @@ struct FunctionBuilder {
81 type_params: Option<ast::TypeParamList>, 81 type_params: Option<ast::TypeParamList>,
82 params: ast::ParamList, 82 params: ast::ParamList,
83 file: AssistFile, 83 file: AssistFile,
84 needs_pub: bool,
84} 85}
85 86
86impl FunctionBuilder { 87impl FunctionBuilder {
@@ -90,11 +91,12 @@ impl FunctionBuilder {
90 ctx: &AssistCtx, 91 ctx: &AssistCtx,
91 call: &ast::CallExpr, 92 call: &ast::CallExpr,
92 path: &ast::Path, 93 path: &ast::Path,
93 generate_in: Option<hir::InFile<hir::ModuleSource>>, 94 target_module: Option<hir::InFile<hir::ModuleSource>>,
94 ) -> Option<Self> { 95 ) -> Option<Self> {
96 let needs_pub = target_module.is_some();
95 let mut file = AssistFile::default(); 97 let mut file = AssistFile::default();
96 let target = if let Some(generate_in_module) = generate_in { 98 let target = if let Some(target_module) = target_module {
97 let (in_file, target) = next_space_for_fn_in_module(ctx.sema.db, generate_in_module)?; 99 let (in_file, target) = next_space_for_fn_in_module(ctx.sema.db, target_module)?;
98 file = in_file; 100 file = in_file;
99 target 101 target
100 } else { 102 } else {
@@ -102,12 +104,16 @@ impl FunctionBuilder {
102 }; 104 };
103 let fn_name = fn_name(&path)?; 105 let fn_name = fn_name(&path)?;
104 let (type_params, params) = fn_args(ctx, &call)?; 106 let (type_params, params) = fn_args(ctx, &call)?;
105 Some(Self { target, fn_name, type_params, params, file }) 107 Some(Self { target, fn_name, type_params, params, file, needs_pub })
106 } 108 }
109
107 fn render(self) -> Option<FunctionTemplate> { 110 fn render(self) -> Option<FunctionTemplate> {
108 let placeholder_expr = ast::make::expr_todo(); 111 let placeholder_expr = ast::make::expr_todo();
109 let fn_body = ast::make::block_expr(vec![], Some(placeholder_expr)); 112 let fn_body = ast::make::block_expr(vec![], Some(placeholder_expr));
110 let fn_def = ast::make::fn_def(self.fn_name, self.type_params, self.params, fn_body); 113 let mut fn_def = ast::make::fn_def(self.fn_name, self.type_params, self.params, fn_body);
114 if self.needs_pub {
115 fn_def = ast::make::add_pub_crate_modifier(fn_def);
116 }
111 117
112 let (fn_def, insert_offset) = match self.target { 118 let (fn_def, insert_offset) = match self.target {
113 GeneratedFunctionTarget::BehindItem(it) => { 119 GeneratedFunctionTarget::BehindItem(it) => {
@@ -116,15 +122,14 @@ impl FunctionBuilder {
116 (indented, it.text_range().end()) 122 (indented, it.text_range().end())
117 } 123 }
118 GeneratedFunctionTarget::InEmptyItemList(it) => { 124 GeneratedFunctionTarget::InEmptyItemList(it) => {
119 let with_leading_newline = ast::make::add_leading_newlines(1, fn_def); 125 let indent_once = IndentLevel(1);
120 let indent = IndentLevel::from_node(it.syntax()).indented(); 126 let indent = IndentLevel::from_node(it.syntax());
121 let mut indented = indent.increase_indent(with_leading_newline); 127
122 if !item_list_has_whitespace(&it) { 128 let fn_def = ast::make::add_leading_newlines(1, fn_def);
123 // In this case we want to make sure there's a newline between the closing 129 let fn_def = indent_once.increase_indent(fn_def);
124 // function brace and the closing module brace (so it doesn't end in `}}`). 130 let fn_def = ast::make::add_trailing_newlines(1, fn_def);
125 indented = ast::make::add_trailing_newlines(1, indented); 131 let fn_def = indent.increase_indent(fn_def);
126 } 132 (fn_def, it.syntax().text_range().start() + TextUnit::from_usize(1))
127 (indented, it.syntax().text_range().start() + TextUnit::from_usize(1))
128 } 133 }
129 }; 134 };
130 135
@@ -140,11 +145,6 @@ impl FunctionBuilder {
140 } 145 }
141} 146}
142 147
143/// Returns true if the given ItemList contains whitespace.
144fn item_list_has_whitespace(it: &ast::ItemList) -> bool {
145 it.syntax().descendants_with_tokens().find(|it| it.kind() == SyntaxKind::WHITESPACE).is_some()
146}
147
148enum GeneratedFunctionTarget { 148enum GeneratedFunctionTarget {
149 BehindItem(SyntaxNode), 149 BehindItem(SyntaxNode),
150 InEmptyItemList(ast::ItemList), 150 InEmptyItemList(ast::ItemList),
@@ -803,29 +803,7 @@ fn foo() {
803", 803",
804 r" 804 r"
805mod bar { 805mod bar {
806 fn my_fn() { 806 pub(crate) fn my_fn() {
807 <|>todo!()
808 }
809}
810
811fn foo() {
812 bar::my_fn()
813}
814",
815 );
816 check_assist(
817 add_function,
818 r"
819mod bar {
820}
821
822fn foo() {
823 bar::my_fn<|>()
824}
825",
826 r"
827mod bar {
828 fn my_fn() {
829 <|>todo!() 807 <|>todo!()
830 } 808 }
831} 809}
@@ -854,7 +832,7 @@ fn foo() {
854mod bar { 832mod bar {
855 fn something_else() {} 833 fn something_else() {}
856 834
857 fn my_fn() { 835 pub(crate) fn my_fn() {
858 <|>todo!() 836 <|>todo!()
859 } 837 }
860} 838}
@@ -872,8 +850,7 @@ fn foo() {
872 add_function, 850 add_function,
873 r" 851 r"
874mod bar { 852mod bar {
875 mod baz { 853 mod baz {}
876 }
877} 854}
878 855
879fn foo() { 856fn foo() {
@@ -883,7 +860,7 @@ fn foo() {
883 r" 860 r"
884mod bar { 861mod bar {
885 mod baz { 862 mod baz {
886 fn my_fn() { 863 pub(crate) fn my_fn() {
887 <|>todo!() 864 <|>todo!()
888 } 865 }
889 } 866 }
diff --git a/crates/ra_syntax/src/ast/make.rs b/crates/ra_syntax/src/ast/make.rs
index b0f4803f3..ee0f5cc40 100644
--- a/crates/ra_syntax/src/ast/make.rs
+++ b/crates/ra_syntax/src/ast/make.rs
@@ -303,6 +303,10 @@ pub fn add_trailing_newlines(amount_of_newlines: usize, t: impl AstNode) -> ast:
303 ast_from_text(&format!("{}{}", t.syntax(), newlines)) 303 ast_from_text(&format!("{}{}", t.syntax(), newlines))
304} 304}
305 305
306pub fn add_pub_crate_modifier(fn_def: ast::FnDef) -> ast::FnDef {
307 ast_from_text(&format!("pub(crate) {}", fn_def))
308}
309
306fn ast_from_text<N: AstNode>(text: &str) -> N { 310fn ast_from_text<N: AstNode>(text: &str) -> N {
307 let parse = SourceFile::parse(text); 311 let parse = SourceFile::parse(text);
308 let node = parse.tree().syntax().descendants().find_map(N::cast).unwrap(); 312 let node = parse.tree().syntax().descendants().find_map(N::cast).unwrap();