diff options
author | Galilée 'Bill' Enguehard <[email protected]> | 2020-05-21 22:27:38 +0100 |
---|---|---|
committer | Galilée 'Bill' Enguehard <[email protected]> | 2020-05-21 22:27:38 +0100 |
commit | 7fece3bdd2450c0807f7dd742239cae95f0cc65e (patch) | |
tree | 866c4db826c959e79c63a6727bdb9f2c61e6fc4f /crates/ra_assists/src/handlers/add_new.rs | |
parent | db926218b2082077750291f8426ddd28b284cd08 (diff) | |
parent | 59732df8d40dfadc6dcf5951265416576399712a (diff) |
Merge branch 'master' of github.com:rust-analyzer/rust-analyzer into modname_spacing
Diffstat (limited to 'crates/ra_assists/src/handlers/add_new.rs')
-rw-r--r-- | crates/ra_assists/src/handlers/add_new.rs | 71 |
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 | }; |
8 | use stdx::{format_to, SepBy}; | 8 | use stdx::{format_to, SepBy}; |
9 | 9 | ||
10 | use crate::{Assist, AssistCtx, AssistId}; | 10 | use 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 | // ``` |
32 | pub(crate) fn add_new(ctx: AssistCtx) -> Option<Assist> { | 32 | pub(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) |
127 | fn find_struct_impl(ctx: &AssistCtx, strukt: &ast::StructDef) -> Option<Option<ast::ImplDef>> { | 124 | fn 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 | ||
163 | fn has_new_fn(imp: &ast::ImplDef) -> bool { | 160 | fn 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)] |
180 | mod tests { | 177 | mod 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 | ||
194 | impl Foo { | 191 | impl 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 | ||
204 | impl<T: Clone> Foo<T> { | 201 | impl<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 | ||
214 | impl<'a, T: Foo<'a>> Foo<'a, T> { | 211 | impl<'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 | ||
224 | impl Foo { | 221 | impl 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 | ||
234 | impl Foo { | 231 | impl 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 | ||
246 | impl Foo { | 243 | impl 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 | ||
261 | impl Foo { | 258 | impl 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 | ||
276 | impl Foo { | 273 | impl 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 | ||
297 | impl Foo { | 294 | impl 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 | ||
314 | impl Foo { | 311 | impl 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 | ||
324 | impl Foo { | 321 | impl 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 | ||
417 | impl<T> Source<T> { | 414 | impl<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) } |