aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src/handlers
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_assists/src/handlers')
-rw-r--r--crates/ra_assists/src/handlers/add_function.rs80
1 files changed, 47 insertions, 33 deletions
diff --git a/crates/ra_assists/src/handlers/add_function.rs b/crates/ra_assists/src/handlers/add_function.rs
index 69fede00f..a0709630d 100644
--- a/crates/ra_assists/src/handlers/add_function.rs
+++ b/crates/ra_assists/src/handlers/add_function.rs
@@ -4,13 +4,13 @@ use ra_syntax::{
4 ast::{ 4 ast::{
5 self, 5 self,
6 edit::{AstNodeEdit, IndentLevel}, 6 edit::{AstNodeEdit, IndentLevel},
7 ArgListOwner, AstNode, ModuleItemOwner, 7 make, ArgListOwner, AstNode, ModuleItemOwner,
8 }, 8 },
9 SyntaxKind, SyntaxNode, TextSize, 9 SyntaxKind, SyntaxNode, TextSize,
10}; 10};
11use rustc_hash::{FxHashMap, FxHashSet}; 11use rustc_hash::{FxHashMap, FxHashSet};
12 12
13use crate::{utils::render_snippet, AssistContext, AssistId, Assists}; 13use crate::{assist_config::SnippetCap, utils::render_snippet, AssistContext, AssistId, Assists};
14 14
15// Assist: add_function 15// Assist: add_function
16// 16//
@@ -61,27 +61,33 @@ pub(crate) fn add_function(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
61 acc.add(AssistId("add_function"), "Add function", target, |builder| { 61 acc.add(AssistId("add_function"), "Add function", target, |builder| {
62 let function_template = function_builder.render(); 62 let function_template = function_builder.render();
63 builder.set_file(function_template.file); 63 builder.set_file(function_template.file);
64 let new_fn = function_template.to_string(ctx.config.snippet_cap);
64 match ctx.config.snippet_cap { 65 match ctx.config.snippet_cap {
65 Some(cap) => { 66 Some(cap) => builder.insert_snippet(cap, function_template.insert_offset, new_fn),
66 let snippet = render_snippet( 67 None => builder.insert(function_template.insert_offset, new_fn),
67 function_template.fn_def.syntax(),
68 function_template.placeholder_expr.syntax(),
69 );
70 builder.insert_snippet(cap, function_template.insert_offset, snippet)
71 }
72 None => builder
73 .insert(function_template.insert_offset, function_template.fn_def.to_string()),
74 } 68 }
75 }) 69 })
76} 70}
77 71
78struct FunctionTemplate { 72struct FunctionTemplate {
79 insert_offset: TextSize, 73 insert_offset: TextSize,
80 fn_def: ast::SourceFile,
81 placeholder_expr: ast::MacroCall, 74 placeholder_expr: ast::MacroCall,
75 leading_ws: String,
76 fn_def: ast::FnDef,
77 trailing_ws: String,
82 file: FileId, 78 file: FileId,
83} 79}
84 80
81impl FunctionTemplate {
82 fn to_string(&self, cap: Option<SnippetCap>) -> String {
83 let f = match cap {
84 Some(cap) => render_snippet(cap, self.fn_def.syntax(), self.placeholder_expr.syntax()),
85 None => self.fn_def.to_string(),
86 };
87 format!("{}{}{}", self.leading_ws, f, self.trailing_ws)
88 }
89}
90
85struct FunctionBuilder { 91struct FunctionBuilder {
86 target: GeneratedFunctionTarget, 92 target: GeneratedFunctionTarget,
87 fn_name: ast::Name, 93 fn_name: ast::Name,
@@ -119,33 +125,41 @@ impl FunctionBuilder {
119 } 125 }
120 126
121 fn render(self) -> FunctionTemplate { 127 fn render(self) -> FunctionTemplate {
122 let placeholder_expr = ast::make::expr_todo(); 128 let placeholder_expr = make::expr_todo();
123 let fn_body = ast::make::block_expr(vec![], Some(placeholder_expr)); 129 let fn_body = make::block_expr(vec![], Some(placeholder_expr));
124 let mut fn_def = ast::make::fn_def(self.fn_name, self.type_params, self.params, fn_body); 130 let visibility = if self.needs_pub { Some(make::visibility_pub_crate()) } else { None };
125 if self.needs_pub { 131 let mut fn_def =
126 fn_def = ast::make::add_pub_crate_modifier(fn_def); 132 make::fn_def(visibility, self.fn_name, self.type_params, self.params, fn_body);
127 } 133 let leading_ws;
128 134 let trailing_ws;
129 let (fn_def, insert_offset) = match self.target { 135
136 let insert_offset = match self.target {
130 GeneratedFunctionTarget::BehindItem(it) => { 137 GeneratedFunctionTarget::BehindItem(it) => {
131 let with_leading_blank_line = ast::make::add_leading_newlines(2, fn_def); 138 let indent = IndentLevel::from_node(&it);
132 let indented = with_leading_blank_line.indent(IndentLevel::from_node(&it)); 139 leading_ws = format!("\n\n{}", indent);
133 (indented, it.text_range().end()) 140 fn_def = fn_def.indent(indent);
141 trailing_ws = String::new();
142 it.text_range().end()
134 } 143 }
135 GeneratedFunctionTarget::InEmptyItemList(it) => { 144 GeneratedFunctionTarget::InEmptyItemList(it) => {
136 let indent_once = IndentLevel(1);
137 let indent = IndentLevel::from_node(it.syntax()); 145 let indent = IndentLevel::from_node(it.syntax());
138 let fn_def = ast::make::add_leading_newlines(1, fn_def); 146 leading_ws = format!("\n{}", indent + 1);
139 let fn_def = fn_def.indent(indent_once); 147 fn_def = fn_def.indent(indent + 1);
140 let fn_def = ast::make::add_trailing_newlines(1, fn_def); 148 trailing_ws = format!("\n{}", indent);
141 let fn_def = fn_def.indent(indent); 149 it.syntax().text_range().start() + TextSize::of('{')
142 (fn_def, it.syntax().text_range().start() + TextSize::of('{'))
143 } 150 }
144 }; 151 };
145 152
146 let placeholder_expr = 153 let placeholder_expr =
147 fn_def.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); 154 fn_def.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
148 FunctionTemplate { insert_offset, placeholder_expr, fn_def, file: self.file } 155 FunctionTemplate {
156 insert_offset,
157 placeholder_expr,
158 leading_ws,
159 fn_def,
160 trailing_ws,
161 file: self.file,
162 }
149 } 163 }
150} 164}
151 165
@@ -165,7 +179,7 @@ impl GeneratedFunctionTarget {
165 179
166fn fn_name(call: &ast::Path) -> Option<ast::Name> { 180fn fn_name(call: &ast::Path) -> Option<ast::Name> {
167 let name = call.segment()?.syntax().to_string(); 181 let name = call.segment()?.syntax().to_string();
168 Some(ast::make::name(&name)) 182 Some(make::name(&name))
169} 183}
170 184
171/// Computes the type variables and arguments required for the generated function 185/// Computes the type variables and arguments required for the generated function
@@ -187,8 +201,8 @@ fn fn_args(
187 }); 201 });
188 } 202 }
189 deduplicate_arg_names(&mut arg_names); 203 deduplicate_arg_names(&mut arg_names);
190 let params = arg_names.into_iter().zip(arg_types).map(|(name, ty)| ast::make::param(name, ty)); 204 let params = arg_names.into_iter().zip(arg_types).map(|(name, ty)| make::param(name, ty));
191 Some((None, ast::make::param_list(params))) 205 Some((None, make::param_list(params)))
192} 206}
193 207
194/// Makes duplicate argument names unique by appending incrementing numbers. 208/// Makes duplicate argument names unique by appending incrementing numbers.