diff options
Diffstat (limited to 'crates/ra_assists/src/handlers')
-rw-r--r-- | crates/ra_assists/src/handlers/add_function.rs | 80 |
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 | }; |
11 | use rustc_hash::{FxHashMap, FxHashSet}; | 11 | use rustc_hash::{FxHashMap, FxHashSet}; |
12 | 12 | ||
13 | use crate::{utils::render_snippet, AssistContext, AssistId, Assists}; | 13 | use 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 | ||
78 | struct FunctionTemplate { | 72 | struct 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 | ||
81 | impl 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 | |||
85 | struct FunctionBuilder { | 91 | struct 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 | ||
166 | fn fn_name(call: &ast::Path) -> Option<ast::Name> { | 180 | fn 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. |