aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists/src/handlers/add_new.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_assists/src/handlers/add_new.rs')
-rw-r--r--crates/ra_assists/src/handlers/add_new.rs71
1 files changed, 34 insertions, 37 deletions
diff --git a/crates/ra_assists/src/handlers/add_new.rs b/crates/ra_assists/src/handlers/add_new.rs
index 0f9174a29..837aa8377 100644
--- a/crates/ra_assists/src/handlers/add_new.rs
+++ b/crates/ra_assists/src/handlers/add_new.rs
@@ -3,11 +3,11 @@ use ra_syntax::{
3 ast::{ 3 ast::{
4 self, AstNode, NameOwner, StructKind, TypeAscriptionOwner, TypeParamsOwner, VisibilityOwner, 4 self, AstNode, NameOwner, StructKind, TypeAscriptionOwner, TypeParamsOwner, VisibilityOwner,
5 }, 5 },
6 TextSize, T, 6 T,
7}; 7};
8use stdx::{format_to, SepBy}; 8use stdx::{format_to, SepBy};
9 9
10use crate::{Assist, AssistCtx, AssistId}; 10use crate::{AssistContext, AssistId, Assists};
11 11
12// Assist: add_new 12// Assist: add_new
13// 13//
@@ -25,11 +25,11 @@ use crate::{Assist, AssistCtx, AssistId};
25// } 25// }
26// 26//
27// impl<T: Clone> Ctx<T> { 27// impl<T: Clone> Ctx<T> {
28// fn new(data: T) -> Self { Self { data } } 28// fn $0new(data: T) -> Self { Self { data } }
29// } 29// }
30// 30//
31// ``` 31// ```
32pub(crate) fn add_new(ctx: AssistCtx) -> Option<Assist> { 32pub(crate) fn add_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
33 let strukt = ctx.find_node_at_offset::<ast::StructDef>()?; 33 let strukt = ctx.find_node_at_offset::<ast::StructDef>()?;
34 34
35 // We want to only apply this to non-union structs with named fields 35 // We want to only apply this to non-union structs with named fields
@@ -41,33 +41,27 @@ pub(crate) fn add_new(ctx: AssistCtx) -> Option<Assist> {
41 // Return early if we've found an existing new fn 41 // Return early if we've found an existing new fn
42 let impl_def = find_struct_impl(&ctx, &strukt)?; 42 let impl_def = find_struct_impl(&ctx, &strukt)?;
43 43
44 ctx.add_assist(AssistId("add_new"), "Add default constructor", |edit| { 44 let target = strukt.syntax().text_range();
45 edit.target(strukt.syntax().text_range()); 45 acc.add(AssistId("add_new"), "Add default constructor", target, |builder| {
46
47 let mut buf = String::with_capacity(512); 46 let mut buf = String::with_capacity(512);
48 47
49 if impl_def.is_some() { 48 if impl_def.is_some() {
50 buf.push('\n'); 49 buf.push('\n');
51 } 50 }
52 51
53 let vis = strukt.visibility().map(|v| format!("{} ", v)); 52 let vis = strukt.visibility().map_or(String::new(), |v| format!("{} ", v));
54 let vis = vis.as_deref().unwrap_or("");
55 53
56 let params = field_list 54 let params = field_list
57 .fields() 55 .fields()
58 .filter_map(|f| { 56 .filter_map(|f| {
59 Some(format!( 57 Some(format!("{}: {}", f.name()?.syntax(), f.ascribed_type()?.syntax()))
60 "{}: {}",
61 f.name()?.syntax().text(),
62 f.ascribed_type()?.syntax().text()
63 ))
64 }) 58 })
65 .sep_by(", "); 59 .sep_by(", ");
66 let fields = field_list.fields().filter_map(|f| f.name()).sep_by(", "); 60 let fields = field_list.fields().filter_map(|f| f.name()).sep_by(", ");
67 61
68 format_to!(buf, " {}fn new({}) -> Self {{ Self {{ {} }} }}", vis, params, fields); 62 format_to!(buf, " {}fn new({}) -> Self {{ Self {{ {} }} }}", vis, params, fields);
69 63
70 let (start_offset, end_offset) = impl_def 64 let start_offset = impl_def
71 .and_then(|impl_def| { 65 .and_then(|impl_def| {
72 buf.push('\n'); 66 buf.push('\n');
73 let start = impl_def 67 let start = impl_def
@@ -77,17 +71,20 @@ pub(crate) fn add_new(ctx: AssistCtx) -> Option<Assist> {
77 .text_range() 71 .text_range()
78 .end(); 72 .end();
79 73
80 Some((start, TextSize::of("\n"))) 74 Some(start)
81 }) 75 })
82 .unwrap_or_else(|| { 76 .unwrap_or_else(|| {
83 buf = generate_impl_text(&strukt, &buf); 77 buf = generate_impl_text(&strukt, &buf);
84 let start = strukt.syntax().text_range().end(); 78 strukt.syntax().text_range().end()
85
86 (start, TextSize::of("\n}\n"))
87 }); 79 });
88 80
89 edit.set_cursor(start_offset + TextSize::of(&buf) - end_offset); 81 match ctx.config.snippet_cap {
90 edit.insert(start_offset, buf); 82 None => builder.insert(start_offset, buf),
83 Some(cap) => {
84 buf = buf.replace("fn new", "fn $0new");
85 builder.insert_snippet(cap, start_offset, buf);
86 }
87 }
91 }) 88 })
92} 89}
93 90
@@ -124,7 +121,7 @@ fn generate_impl_text(strukt: &ast::StructDef, code: &str) -> String {
124// 121//
125// FIXME: change the new fn checking to a more semantic approach when that's more 122// FIXME: change the new fn checking to a more semantic approach when that's more
126// viable (e.g. we process proc macros, etc) 123// viable (e.g. we process proc macros, etc)
127fn find_struct_impl(ctx: &AssistCtx, strukt: &ast::StructDef) -> Option<Option<ast::ImplDef>> { 124fn find_struct_impl(ctx: &AssistContext, strukt: &ast::StructDef) -> Option<Option<ast::ImplDef>> {
128 let db = ctx.db; 125 let db = ctx.db;
129 let module = strukt.syntax().ancestors().find(|node| { 126 let module = strukt.syntax().ancestors().find(|node| {
130 ast::Module::can_cast(node.kind()) || ast::SourceFile::can_cast(node.kind()) 127 ast::Module::can_cast(node.kind()) || ast::SourceFile::can_cast(node.kind())
@@ -162,8 +159,8 @@ fn find_struct_impl(ctx: &AssistCtx, strukt: &ast::StructDef) -> Option<Option<a
162 159
163fn has_new_fn(imp: &ast::ImplDef) -> bool { 160fn has_new_fn(imp: &ast::ImplDef) -> bool {
164 if let Some(il) = imp.item_list() { 161 if let Some(il) = imp.item_list() {
165 for item in il.impl_items() { 162 for item in il.assoc_items() {
166 if let ast::ImplItem::FnDef(f) = item { 163 if let ast::AssocItem::FnDef(f) = item {
167 if let Some(name) = f.name() { 164 if let Some(name) = f.name() {
168 if name.text().eq_ignore_ascii_case("new") { 165 if name.text().eq_ignore_ascii_case("new") {
169 return true; 166 return true;
@@ -178,7 +175,7 @@ fn has_new_fn(imp: &ast::ImplDef) -> bool {
178 175
179#[cfg(test)] 176#[cfg(test)]
180mod tests { 177mod tests {
181 use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target}; 178 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
182 179
183 use super::*; 180 use super::*;
184 181
@@ -192,7 +189,7 @@ mod tests {
192"struct Foo {} 189"struct Foo {}
193 190
194impl Foo { 191impl Foo {
195 fn new() -> Self { Self { } }<|> 192 fn $0new() -> Self { Self { } }
196} 193}
197", 194",
198 ); 195 );
@@ -202,7 +199,7 @@ impl Foo {
202"struct Foo<T: Clone> {} 199"struct Foo<T: Clone> {}
203 200
204impl<T: Clone> Foo<T> { 201impl<T: Clone> Foo<T> {
205 fn new() -> Self { Self { } }<|> 202 fn $0new() -> Self { Self { } }
206} 203}
207", 204",
208 ); 205 );
@@ -212,7 +209,7 @@ impl<T: Clone> Foo<T> {
212"struct Foo<'a, T: Foo<'a>> {} 209"struct Foo<'a, T: Foo<'a>> {}
213 210
214impl<'a, T: Foo<'a>> Foo<'a, T> { 211impl<'a, T: Foo<'a>> Foo<'a, T> {
215 fn new() -> Self { Self { } }<|> 212 fn $0new() -> Self { Self { } }
216} 213}
217", 214",
218 ); 215 );
@@ -222,7 +219,7 @@ impl<'a, T: Foo<'a>> Foo<'a, T> {
222"struct Foo { baz: String } 219"struct Foo { baz: String }
223 220
224impl Foo { 221impl Foo {
225 fn new(baz: String) -> Self { Self { baz } }<|> 222 fn $0new(baz: String) -> Self { Self { baz } }
226} 223}
227", 224",
228 ); 225 );
@@ -232,7 +229,7 @@ impl Foo {
232"struct Foo { baz: String, qux: Vec<i32> } 229"struct Foo { baz: String, qux: Vec<i32> }
233 230
234impl Foo { 231impl Foo {
235 fn new(baz: String, qux: Vec<i32>) -> Self { Self { baz, qux } }<|> 232 fn $0new(baz: String, qux: Vec<i32>) -> Self { Self { baz, qux } }
236} 233}
237", 234",
238 ); 235 );
@@ -244,7 +241,7 @@ impl Foo {
244"struct Foo { pub baz: String, pub qux: Vec<i32> } 241"struct Foo { pub baz: String, pub qux: Vec<i32> }
245 242
246impl Foo { 243impl Foo {
247 fn new(baz: String, qux: Vec<i32>) -> Self { Self { baz, qux } }<|> 244 fn $0new(baz: String, qux: Vec<i32>) -> Self { Self { baz, qux } }
248} 245}
249", 246",
250 ); 247 );
@@ -259,7 +256,7 @@ impl Foo {}
259"struct Foo {} 256"struct Foo {}
260 257
261impl Foo { 258impl Foo {
262 fn new() -> Self { Self { } }<|> 259 fn $0new() -> Self { Self { } }
263} 260}
264", 261",
265 ); 262 );
@@ -274,7 +271,7 @@ impl Foo {
274"struct Foo {} 271"struct Foo {}
275 272
276impl Foo { 273impl Foo {
277 fn new() -> Self { Self { } }<|> 274 fn $0new() -> Self { Self { } }
278 275
279 fn qux(&self) {} 276 fn qux(&self) {}
280} 277}
@@ -295,7 +292,7 @@ impl Foo {
295"struct Foo {} 292"struct Foo {}
296 293
297impl Foo { 294impl Foo {
298 fn new() -> Self { Self { } }<|> 295 fn $0new() -> Self { Self { } }
299 296
300 fn qux(&self) {} 297 fn qux(&self) {}
301 fn baz() -> i32 { 298 fn baz() -> i32 {
@@ -312,7 +309,7 @@ impl Foo {
312"pub struct Foo {} 309"pub struct Foo {}
313 310
314impl Foo { 311impl Foo {
315 pub fn new() -> Self { Self { } }<|> 312 pub fn $0new() -> Self { Self { } }
316} 313}
317", 314",
318 ); 315 );
@@ -322,7 +319,7 @@ impl Foo {
322"pub(crate) struct Foo {} 319"pub(crate) struct Foo {}
323 320
324impl Foo { 321impl Foo {
325 pub(crate) fn new() -> Self { Self { } }<|> 322 pub(crate) fn $0new() -> Self { Self { } }
326} 323}
327", 324",
328 ); 325 );
@@ -415,7 +412,7 @@ pub struct Source<T> {
415} 412}
416 413
417impl<T> Source<T> { 414impl<T> Source<T> {
418 pub fn new(file_id: HirFileId, ast: T) -> Self { Self { file_id, ast } }<|> 415 pub fn $0new(file_id: HirFileId, ast: T) -> Self { Self { file_id, ast } }
419 416
420 pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> { 417 pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
421 Source { file_id: self.file_id, ast: f(self.ast) } 418 Source { file_id: self.file_id, ast: f(self.ast) }