aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_assists
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_assists')
-rw-r--r--crates/ra_assists/src/assist_config.rs27
-rw-r--r--crates/ra_assists/src/assist_context.rs41
-rw-r--r--crates/ra_assists/src/handlers/add_custom_impl.rs51
-rw-r--r--crates/ra_assists/src/handlers/add_derive.rs28
-rw-r--r--crates/ra_assists/src/handlers/add_impl.rs34
-rw-r--r--crates/ra_assists/src/lib.rs15
-rw-r--r--crates/ra_assists/src/tests.rs38
-rw-r--r--crates/ra_assists/src/tests/generated.rs10
8 files changed, 160 insertions, 84 deletions
diff --git a/crates/ra_assists/src/assist_config.rs b/crates/ra_assists/src/assist_config.rs
new file mode 100644
index 000000000..c0a0226fb
--- /dev/null
+++ b/crates/ra_assists/src/assist_config.rs
@@ -0,0 +1,27 @@
1//! Settings for tweaking assists.
2//!
3//! The fun thing here is `SnippetCap` -- this type can only be created in this
4//! module, and we use to statically check that we only produce snippet
5//! assists if we are allowed to.
6
7#[derive(Clone, Debug, PartialEq, Eq)]
8pub struct AssistConfig {
9 pub snippet_cap: Option<SnippetCap>,
10}
11
12impl AssistConfig {
13 pub fn allow_snippets(&mut self, yes: bool) {
14 self.snippet_cap = if yes { Some(SnippetCap { _private: () }) } else { None }
15 }
16}
17
18#[derive(Clone, Copy, Debug, PartialEq, Eq)]
19pub struct SnippetCap {
20 _private: (),
21}
22
23impl Default for AssistConfig {
24 fn default() -> Self {
25 AssistConfig { snippet_cap: Some(SnippetCap { _private: () }) }
26 }
27}
diff --git a/crates/ra_assists/src/assist_context.rs b/crates/ra_assists/src/assist_context.rs
index a680f752b..0dcd9df61 100644
--- a/crates/ra_assists/src/assist_context.rs
+++ b/crates/ra_assists/src/assist_context.rs
@@ -15,7 +15,10 @@ use ra_syntax::{
15}; 15};
16use ra_text_edit::TextEditBuilder; 16use ra_text_edit::TextEditBuilder;
17 17
18use crate::{Assist, AssistId, GroupLabel, ResolvedAssist}; 18use crate::{
19 assist_config::{AssistConfig, SnippetCap},
20 Assist, AssistId, GroupLabel, ResolvedAssist,
21};
19 22
20/// `AssistContext` allows to apply an assist or check if it could be applied. 23/// `AssistContext` allows to apply an assist or check if it could be applied.
21/// 24///
@@ -48,6 +51,7 @@ use crate::{Assist, AssistId, GroupLabel, ResolvedAssist};
48/// moment, because the LSP API is pretty awkward in this place, and it's much 51/// moment, because the LSP API is pretty awkward in this place, and it's much
49/// easier to just compute the edit eagerly :-) 52/// easier to just compute the edit eagerly :-)
50pub(crate) struct AssistContext<'a> { 53pub(crate) struct AssistContext<'a> {
54 pub(crate) config: &'a AssistConfig,
51 pub(crate) sema: Semantics<'a, RootDatabase>, 55 pub(crate) sema: Semantics<'a, RootDatabase>,
52 pub(crate) db: &'a RootDatabase, 56 pub(crate) db: &'a RootDatabase,
53 pub(crate) frange: FileRange, 57 pub(crate) frange: FileRange,
@@ -55,10 +59,14 @@ pub(crate) struct AssistContext<'a> {
55} 59}
56 60
57impl<'a> AssistContext<'a> { 61impl<'a> AssistContext<'a> {
58 pub fn new(sema: Semantics<'a, RootDatabase>, frange: FileRange) -> AssistContext<'a> { 62 pub(crate) fn new(
63 sema: Semantics<'a, RootDatabase>,
64 config: &'a AssistConfig,
65 frange: FileRange,
66 ) -> AssistContext<'a> {
59 let source_file = sema.parse(frange.file_id); 67 let source_file = sema.parse(frange.file_id);
60 let db = sema.db; 68 let db = sema.db;
61 AssistContext { sema, db, frange, source_file } 69 AssistContext { config, sema, db, frange, source_file }
62 } 70 }
63 71
64 // NB, this ignores active selection. 72 // NB, this ignores active selection.
@@ -165,11 +173,17 @@ pub(crate) struct AssistBuilder {
165 edit: TextEditBuilder, 173 edit: TextEditBuilder,
166 cursor_position: Option<TextSize>, 174 cursor_position: Option<TextSize>,
167 file: FileId, 175 file: FileId,
176 is_snippet: bool,
168} 177}
169 178
170impl AssistBuilder { 179impl AssistBuilder {
171 pub(crate) fn new(file: FileId) -> AssistBuilder { 180 pub(crate) fn new(file: FileId) -> AssistBuilder {
172 AssistBuilder { edit: TextEditBuilder::default(), cursor_position: None, file } 181 AssistBuilder {
182 edit: TextEditBuilder::default(),
183 cursor_position: None,
184 file,
185 is_snippet: false,
186 }
173 } 187 }
174 188
175 /// Remove specified `range` of text. 189 /// Remove specified `range` of text.
@@ -180,6 +194,16 @@ impl AssistBuilder {
180 pub(crate) fn insert(&mut self, offset: TextSize, text: impl Into<String>) { 194 pub(crate) fn insert(&mut self, offset: TextSize, text: impl Into<String>) {
181 self.edit.insert(offset, text.into()) 195 self.edit.insert(offset, text.into())
182 } 196 }
197 /// Append specified `text` at the given `offset`
198 pub(crate) fn insert_snippet(
199 &mut self,
200 _cap: SnippetCap,
201 offset: TextSize,
202 text: impl Into<String>,
203 ) {
204 self.is_snippet = true;
205 self.edit.insert(offset, text.into())
206 }
183 /// Replaces specified `range` of text with a given string. 207 /// Replaces specified `range` of text with a given string.
184 pub(crate) fn replace(&mut self, range: TextRange, replace_with: impl Into<String>) { 208 pub(crate) fn replace(&mut self, range: TextRange, replace_with: impl Into<String>) {
185 self.edit.replace(range, replace_with.into()) 209 self.edit.replace(range, replace_with.into())
@@ -227,7 +251,12 @@ impl AssistBuilder {
227 if edit.is_empty() && self.cursor_position.is_none() { 251 if edit.is_empty() && self.cursor_position.is_none() {
228 panic!("Only call `add_assist` if the assist can be applied") 252 panic!("Only call `add_assist` if the assist can be applied")
229 } 253 }
230 SingleFileChange { label: change_label, edit, cursor_position: self.cursor_position } 254 let mut res =
231 .into_source_change(self.file) 255 SingleFileChange { label: change_label, edit, cursor_position: self.cursor_position }
256 .into_source_change(self.file);
257 if self.is_snippet {
258 res.is_snippet = true;
259 }
260 res
232 } 261 }
233} 262}
diff --git a/crates/ra_assists/src/handlers/add_custom_impl.rs b/crates/ra_assists/src/handlers/add_custom_impl.rs
index 2baeb8607..fa70c8496 100644
--- a/crates/ra_assists/src/handlers/add_custom_impl.rs
+++ b/crates/ra_assists/src/handlers/add_custom_impl.rs
@@ -25,7 +25,7 @@ use crate::{
25// struct S; 25// struct S;
26// 26//
27// impl Debug for S { 27// impl Debug for S {
28// 28// $0
29// } 29// }
30// ``` 30// ```
31pub(crate) fn add_custom_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 31pub(crate) fn add_custom_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
@@ -52,7 +52,7 @@ pub(crate) fn add_custom_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<
52 format!("Add custom impl `{}` for `{}`", trait_token.text().as_str(), annotated_name); 52 format!("Add custom impl `{}` for `{}`", trait_token.text().as_str(), annotated_name);
53 53
54 let target = attr.syntax().text_range(); 54 let target = attr.syntax().text_range();
55 acc.add(AssistId("add_custom_impl"), label, target, |edit| { 55 acc.add(AssistId("add_custom_impl"), label, target, |builder| {
56 let new_attr_input = input 56 let new_attr_input = input
57 .syntax() 57 .syntax()
58 .descendants_with_tokens() 58 .descendants_with_tokens()
@@ -63,20 +63,11 @@ pub(crate) fn add_custom_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<
63 let has_more_derives = !new_attr_input.is_empty(); 63 let has_more_derives = !new_attr_input.is_empty();
64 let new_attr_input = new_attr_input.iter().sep_by(", ").surround_with("(", ")").to_string(); 64 let new_attr_input = new_attr_input.iter().sep_by(", ").surround_with("(", ")").to_string();
65 65
66 let mut buf = String::new(); 66 if has_more_derives {
67 buf.push_str("\n\nimpl "); 67 builder.replace(input.syntax().text_range(), new_attr_input);
68 buf.push_str(trait_token.text().as_str());
69 buf.push_str(" for ");
70 buf.push_str(annotated_name.as_str());
71 buf.push_str(" {\n");
72
73 let cursor_delta = if has_more_derives {
74 let delta = input.syntax().text_range().len() - TextSize::of(&new_attr_input);
75 edit.replace(input.syntax().text_range(), new_attr_input);
76 delta
77 } else { 68 } else {
78 let attr_range = attr.syntax().text_range(); 69 let attr_range = attr.syntax().text_range();
79 edit.delete(attr_range); 70 builder.delete(attr_range);
80 71
81 let line_break_range = attr 72 let line_break_range = attr
82 .syntax() 73 .syntax()
@@ -84,14 +75,24 @@ pub(crate) fn add_custom_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<
84 .filter(|t| t.kind() == WHITESPACE) 75 .filter(|t| t.kind() == WHITESPACE)
85 .map(|t| t.text_range()) 76 .map(|t| t.text_range())
86 .unwrap_or_else(|| TextRange::new(TextSize::from(0), TextSize::from(0))); 77 .unwrap_or_else(|| TextRange::new(TextSize::from(0), TextSize::from(0)));
87 edit.delete(line_break_range); 78 builder.delete(line_break_range);
88 79 }
89 attr_range.len() + line_break_range.len() 80
90 }; 81 match ctx.config.snippet_cap {
91 82 Some(cap) => {
92 edit.set_cursor(start_offset + TextSize::of(&buf) - cursor_delta); 83 builder.insert_snippet(
93 buf.push_str("\n}"); 84 cap,
94 edit.insert(start_offset, buf); 85 start_offset,
86 format!("\n\nimpl {} for {} {{\n $0\n}}", trait_token, annotated_name),
87 );
88 }
89 None => {
90 builder.insert(
91 start_offset,
92 format!("\n\nimpl {} for {} {{\n\n}}", trait_token, annotated_name),
93 );
94 }
95 }
95 }) 96 })
96} 97}
97 98
@@ -117,7 +118,7 @@ struct Foo {
117} 118}
118 119
119impl Debug for Foo { 120impl Debug for Foo {
120<|> 121 $0
121} 122}
122 ", 123 ",
123 ) 124 )
@@ -139,7 +140,7 @@ pub struct Foo {
139} 140}
140 141
141impl Debug for Foo { 142impl Debug for Foo {
142<|> 143 $0
143} 144}
144 ", 145 ",
145 ) 146 )
@@ -158,7 +159,7 @@ struct Foo {}
158struct Foo {} 159struct Foo {}
159 160
160impl Debug for Foo { 161impl Debug for Foo {
161<|> 162 $0
162} 163}
163 ", 164 ",
164 ) 165 )
diff --git a/crates/ra_assists/src/handlers/add_derive.rs b/crates/ra_assists/src/handlers/add_derive.rs
index fb08c19e9..b123b8498 100644
--- a/crates/ra_assists/src/handlers/add_derive.rs
+++ b/crates/ra_assists/src/handlers/add_derive.rs
@@ -18,31 +18,37 @@ use crate::{AssistContext, AssistId, Assists};
18// ``` 18// ```
19// -> 19// ->
20// ``` 20// ```
21// #[derive()] 21// #[derive($0)]
22// struct Point { 22// struct Point {
23// x: u32, 23// x: u32,
24// y: u32, 24// y: u32,
25// } 25// }
26// ``` 26// ```
27pub(crate) fn add_derive(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 27pub(crate) fn add_derive(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
28 let cap = ctx.config.snippet_cap?;
28 let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?; 29 let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?;
29 let node_start = derive_insertion_offset(&nominal)?; 30 let node_start = derive_insertion_offset(&nominal)?;
30 let target = nominal.syntax().text_range(); 31 let target = nominal.syntax().text_range();
31 acc.add(AssistId("add_derive"), "Add `#[derive]`", target, |edit| { 32 acc.add(AssistId("add_derive"), "Add `#[derive]`", target, |builder| {
32 let derive_attr = nominal 33 let derive_attr = nominal
33 .attrs() 34 .attrs()
34 .filter_map(|x| x.as_simple_call()) 35 .filter_map(|x| x.as_simple_call())
35 .filter(|(name, _arg)| name == "derive") 36 .filter(|(name, _arg)| name == "derive")
36 .map(|(_name, arg)| arg) 37 .map(|(_name, arg)| arg)
37 .next(); 38 .next();
38 let offset = match derive_attr { 39 match derive_attr {
39 None => { 40 None => {
40 edit.insert(node_start, "#[derive()]\n"); 41 builder.insert_snippet(cap, node_start, "#[derive($0)]\n");
41 node_start + TextSize::of("#[derive(") 42 }
43 Some(tt) => {
44 // Just move the cursor.
45 builder.insert_snippet(
46 cap,
47 tt.syntax().text_range().end() - TextSize::of(')'),
48 "$0",
49 )
42 } 50 }
43 Some(tt) => tt.syntax().text_range().end() - TextSize::of(')'),
44 }; 51 };
45 edit.set_cursor(offset)
46 }) 52 })
47} 53}
48 54
@@ -66,12 +72,12 @@ mod tests {
66 check_assist( 72 check_assist(
67 add_derive, 73 add_derive,
68 "struct Foo { a: i32, <|>}", 74 "struct Foo { a: i32, <|>}",
69 "#[derive(<|>)]\nstruct Foo { a: i32, }", 75 "#[derive($0)]\nstruct Foo { a: i32, }",
70 ); 76 );
71 check_assist( 77 check_assist(
72 add_derive, 78 add_derive,
73 "struct Foo { <|> a: i32, }", 79 "struct Foo { <|> a: i32, }",
74 "#[derive(<|>)]\nstruct Foo { a: i32, }", 80 "#[derive($0)]\nstruct Foo { a: i32, }",
75 ); 81 );
76 } 82 }
77 83
@@ -80,7 +86,7 @@ mod tests {
80 check_assist( 86 check_assist(
81 add_derive, 87 add_derive,
82 "#[derive(Clone)]\nstruct Foo { a: i32<|>, }", 88 "#[derive(Clone)]\nstruct Foo { a: i32<|>, }",
83 "#[derive(Clone<|>)]\nstruct Foo { a: i32, }", 89 "#[derive(Clone$0)]\nstruct Foo { a: i32, }",
84 ); 90 );
85 } 91 }
86 92
@@ -96,7 +102,7 @@ struct Foo { a: i32<|>, }
96 " 102 "
97/// `Foo` is a pretty important struct. 103/// `Foo` is a pretty important struct.
98/// It does stuff. 104/// It does stuff.
99#[derive(<|>)] 105#[derive($0)]
100struct Foo { a: i32, } 106struct Foo { a: i32, }
101 ", 107 ",
102 ); 108 );
diff --git a/crates/ra_assists/src/handlers/add_impl.rs b/crates/ra_assists/src/handlers/add_impl.rs
index df114a0d8..eceba7d0a 100644
--- a/crates/ra_assists/src/handlers/add_impl.rs
+++ b/crates/ra_assists/src/handlers/add_impl.rs
@@ -1,7 +1,4 @@
1use ra_syntax::{ 1use ra_syntax::ast::{self, AstNode, NameOwner, TypeParamsOwner};
2 ast::{self, AstNode, NameOwner, TypeParamsOwner},
3 TextSize,
4};
5use stdx::{format_to, SepBy}; 2use stdx::{format_to, SepBy};
6 3
7use crate::{AssistContext, AssistId, Assists}; 4use crate::{AssistContext, AssistId, Assists};
@@ -12,17 +9,17 @@ use crate::{AssistContext, AssistId, Assists};
12// 9//
13// ``` 10// ```
14// struct Ctx<T: Clone> { 11// struct Ctx<T: Clone> {
15// data: T,<|> 12// data: T,<|>
16// } 13// }
17// ``` 14// ```
18// -> 15// ->
19// ``` 16// ```
20// struct Ctx<T: Clone> { 17// struct Ctx<T: Clone> {
21// data: T, 18// data: T,
22// } 19// }
23// 20//
24// impl<T: Clone> Ctx<T> { 21// impl<T: Clone> Ctx<T> {
25// 22// $0
26// } 23// }
27// ``` 24// ```
28pub(crate) fn add_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 25pub(crate) fn add_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
@@ -50,30 +47,37 @@ pub(crate) fn add_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
50 let generic_params = lifetime_params.chain(type_params).sep_by(", "); 47 let generic_params = lifetime_params.chain(type_params).sep_by(", ");
51 format_to!(buf, "<{}>", generic_params) 48 format_to!(buf, "<{}>", generic_params)
52 } 49 }
53 buf.push_str(" {\n"); 50 match ctx.config.snippet_cap {
54 edit.set_cursor(start_offset + TextSize::of(&buf)); 51 Some(cap) => {
55 buf.push_str("\n}"); 52 buf.push_str(" {\n $0\n}");
56 edit.insert(start_offset, buf); 53 edit.insert_snippet(cap, start_offset, buf);
54 }
55 None => {
56 buf.push_str(" {\n}");
57 edit.insert(start_offset, buf);
58 }
59 }
57 }) 60 })
58} 61}
59 62
60#[cfg(test)] 63#[cfg(test)]
61mod tests { 64mod tests {
62 use super::*;
63 use crate::tests::{check_assist, check_assist_target}; 65 use crate::tests::{check_assist, check_assist_target};
64 66
67 use super::*;
68
65 #[test] 69 #[test]
66 fn test_add_impl() { 70 fn test_add_impl() {
67 check_assist(add_impl, "struct Foo {<|>}\n", "struct Foo {}\n\nimpl Foo {\n<|>\n}\n"); 71 check_assist(add_impl, "struct Foo {<|>}\n", "struct Foo {}\n\nimpl Foo {\n $0\n}\n");
68 check_assist( 72 check_assist(
69 add_impl, 73 add_impl,
70 "struct Foo<T: Clone> {<|>}", 74 "struct Foo<T: Clone> {<|>}",
71 "struct Foo<T: Clone> {}\n\nimpl<T: Clone> Foo<T> {\n<|>\n}", 75 "struct Foo<T: Clone> {}\n\nimpl<T: Clone> Foo<T> {\n $0\n}",
72 ); 76 );
73 check_assist( 77 check_assist(
74 add_impl, 78 add_impl,
75 "struct Foo<'a, T: Foo<'a>> {<|>}", 79 "struct Foo<'a, T: Foo<'a>> {<|>}",
76 "struct Foo<'a, T: Foo<'a>> {}\n\nimpl<'a, T: Foo<'a>> Foo<'a, T> {\n<|>\n}", 80 "struct Foo<'a, T: Foo<'a>> {}\n\nimpl<'a, T: Foo<'a>> Foo<'a, T> {\n $0\n}",
77 ); 81 );
78 } 82 }
79 83
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs
index b6dc7cb1b..7f0a723c9 100644
--- a/crates/ra_assists/src/lib.rs
+++ b/crates/ra_assists/src/lib.rs
@@ -10,6 +10,7 @@ macro_rules! eprintln {
10 ($($tt:tt)*) => { stdx::eprintln!($($tt)*) }; 10 ($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
11} 11}
12 12
13mod assist_config;
13mod assist_context; 14mod assist_context;
14mod marks; 15mod marks;
15#[cfg(test)] 16#[cfg(test)]
@@ -24,6 +25,8 @@ use ra_syntax::TextRange;
24 25
25pub(crate) use crate::assist_context::{AssistContext, Assists}; 26pub(crate) use crate::assist_context::{AssistContext, Assists};
26 27
28pub use assist_config::AssistConfig;
29
27/// Unique identifier of the assist, should not be shown to the user 30/// Unique identifier of the assist, should not be shown to the user
28/// directly. 31/// directly.
29#[derive(Debug, Clone, Copy, PartialEq, Eq)] 32#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -54,9 +57,9 @@ impl Assist {
54 /// 57 ///
55 /// Assists are returned in the "unresolved" state, that is only labels are 58 /// Assists are returned in the "unresolved" state, that is only labels are
56 /// returned, without actual edits. 59 /// returned, without actual edits.
57 pub fn unresolved(db: &RootDatabase, range: FileRange) -> Vec<Assist> { 60 pub fn unresolved(db: &RootDatabase, config: &AssistConfig, range: FileRange) -> Vec<Assist> {
58 let sema = Semantics::new(db); 61 let sema = Semantics::new(db);
59 let ctx = AssistContext::new(sema, range); 62 let ctx = AssistContext::new(sema, config, range);
60 let mut acc = Assists::new_unresolved(&ctx); 63 let mut acc = Assists::new_unresolved(&ctx);
61 handlers::all().iter().for_each(|handler| { 64 handlers::all().iter().for_each(|handler| {
62 handler(&mut acc, &ctx); 65 handler(&mut acc, &ctx);
@@ -68,9 +71,13 @@ impl Assist {
68 /// 71 ///
69 /// Assists are returned in the "resolved" state, that is with edit fully 72 /// Assists are returned in the "resolved" state, that is with edit fully
70 /// computed. 73 /// computed.
71 pub fn resolved(db: &RootDatabase, range: FileRange) -> Vec<ResolvedAssist> { 74 pub fn resolved(
75 db: &RootDatabase,
76 config: &AssistConfig,
77 range: FileRange,
78 ) -> Vec<ResolvedAssist> {
72 let sema = Semantics::new(db); 79 let sema = Semantics::new(db);
73 let ctx = AssistContext::new(sema, range); 80 let ctx = AssistContext::new(sema, config, range);
74 let mut acc = Assists::new_resolved(&ctx); 81 let mut acc = Assists::new_resolved(&ctx);
75 handlers::all().iter().for_each(|handler| { 82 handlers::all().iter().for_each(|handler| {
76 handler(&mut acc, &ctx); 83 handler(&mut acc, &ctx);
diff --git a/crates/ra_assists/src/tests.rs b/crates/ra_assists/src/tests.rs
index a3eacb8f1..9ba3da786 100644
--- a/crates/ra_assists/src/tests.rs
+++ b/crates/ra_assists/src/tests.rs
@@ -11,7 +11,7 @@ use test_utils::{
11 RangeOrOffset, 11 RangeOrOffset,
12}; 12};
13 13
14use crate::{handlers::Handler, Assist, AssistContext, Assists}; 14use crate::{handlers::Handler, Assist, AssistConfig, AssistContext, Assists};
15 15
16pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) { 16pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) {
17 let (mut db, file_id) = RootDatabase::with_single_file(text); 17 let (mut db, file_id) = RootDatabase::with_single_file(text);
@@ -41,14 +41,14 @@ fn check_doc_test(assist_id: &str, before: &str, after: &str) {
41 let (db, file_id) = crate::tests::with_single_file(&before); 41 let (db, file_id) = crate::tests::with_single_file(&before);
42 let frange = FileRange { file_id, range: selection.into() }; 42 let frange = FileRange { file_id, range: selection.into() };
43 43
44 let mut assist = Assist::resolved(&db, frange) 44 let mut assist = Assist::resolved(&db, &AssistConfig::default(), frange)
45 .into_iter() 45 .into_iter()
46 .find(|assist| assist.assist.id.0 == assist_id) 46 .find(|assist| assist.assist.id.0 == assist_id)
47 .unwrap_or_else(|| { 47 .unwrap_or_else(|| {
48 panic!( 48 panic!(
49 "\n\nAssist is not applicable: {}\nAvailable assists: {}", 49 "\n\nAssist is not applicable: {}\nAvailable assists: {}",
50 assist_id, 50 assist_id,
51 Assist::resolved(&db, frange) 51 Assist::resolved(&db, &AssistConfig::default(), frange)
52 .into_iter() 52 .into_iter()
53 .map(|assist| assist.assist.id.0) 53 .map(|assist| assist.assist.id.0)
54 .collect::<Vec<_>>() 54 .collect::<Vec<_>>()
@@ -90,7 +90,8 @@ fn check(handler: Handler, before: &str, expected: ExpectedResult) {
90 let frange = FileRange { file_id: file_with_caret_id, range: range_or_offset.into() }; 90 let frange = FileRange { file_id: file_with_caret_id, range: range_or_offset.into() };
91 91
92 let sema = Semantics::new(&db); 92 let sema = Semantics::new(&db);
93 let ctx = AssistContext::new(sema, frange); 93 let config = AssistConfig::default();
94 let ctx = AssistContext::new(sema, &config, frange);
94 let mut acc = Assists::new_resolved(&ctx); 95 let mut acc = Assists::new_resolved(&ctx);
95 handler(&mut acc, &ctx); 96 handler(&mut acc, &ctx);
96 let mut res = acc.finish_resolved(); 97 let mut res = acc.finish_resolved();
@@ -103,19 +104,20 @@ fn check(handler: Handler, before: &str, expected: ExpectedResult) {
103 let mut actual = db.file_text(change.file_id).as_ref().to_owned(); 104 let mut actual = db.file_text(change.file_id).as_ref().to_owned();
104 change.edit.apply(&mut actual); 105 change.edit.apply(&mut actual);
105 106
106 match source_change.cursor_position { 107 if !source_change.is_snippet {
107 None => { 108 match source_change.cursor_position {
108 if let RangeOrOffset::Offset(before_cursor_pos) = range_or_offset { 109 None => {
109 let off = change 110 if let RangeOrOffset::Offset(before_cursor_pos) = range_or_offset {
110 .edit 111 let off = change
111 .apply_to_offset(before_cursor_pos) 112 .edit
112 .expect("cursor position is affected by the edit"); 113 .apply_to_offset(before_cursor_pos)
113 actual = add_cursor(&actual, off) 114 .expect("cursor position is affected by the edit");
115 actual = add_cursor(&actual, off)
116 }
114 } 117 }
115 } 118 Some(off) => actual = add_cursor(&actual, off.offset),
116 Some(off) => actual = add_cursor(&actual, off.offset), 119 };
117 }; 120 }
118
119 assert_eq_text!(after, &actual); 121 assert_eq_text!(after, &actual);
120 } 122 }
121 (Some(assist), ExpectedResult::Target(target)) => { 123 (Some(assist), ExpectedResult::Target(target)) => {
@@ -136,7 +138,7 @@ fn assist_order_field_struct() {
136 let (before_cursor_pos, before) = extract_offset(before); 138 let (before_cursor_pos, before) = extract_offset(before);
137 let (db, file_id) = with_single_file(&before); 139 let (db, file_id) = with_single_file(&before);
138 let frange = FileRange { file_id, range: TextRange::empty(before_cursor_pos) }; 140 let frange = FileRange { file_id, range: TextRange::empty(before_cursor_pos) };
139 let assists = Assist::resolved(&db, frange); 141 let assists = Assist::resolved(&db, &AssistConfig::default(), frange);
140 let mut assists = assists.iter(); 142 let mut assists = assists.iter();
141 143
142 assert_eq!( 144 assert_eq!(
@@ -159,7 +161,7 @@ fn assist_order_if_expr() {
159 let (range, before) = extract_range(before); 161 let (range, before) = extract_range(before);
160 let (db, file_id) = with_single_file(&before); 162 let (db, file_id) = with_single_file(&before);
161 let frange = FileRange { file_id, range }; 163 let frange = FileRange { file_id, range };
162 let assists = Assist::resolved(&db, frange); 164 let assists = Assist::resolved(&db, &AssistConfig::default(), frange);
163 let mut assists = assists.iter(); 165 let mut assists = assists.iter();
164 166
165 assert_eq!(assists.next().expect("expected assist").assist.label, "Extract into variable"); 167 assert_eq!(assists.next().expect("expected assist").assist.label, "Extract into variable");
diff --git a/crates/ra_assists/src/tests/generated.rs b/crates/ra_assists/src/tests/generated.rs
index 972dbd251..9487c9239 100644
--- a/crates/ra_assists/src/tests/generated.rs
+++ b/crates/ra_assists/src/tests/generated.rs
@@ -15,7 +15,7 @@ struct S;
15struct S; 15struct S;
16 16
17impl Debug for S { 17impl Debug for S {
18 18 $0
19} 19}
20"#####, 20"#####,
21 ) 21 )
@@ -32,7 +32,7 @@ struct Point {
32} 32}
33"#####, 33"#####,
34 r#####" 34 r#####"
35#[derive()] 35#[derive($0)]
36struct Point { 36struct Point {
37 x: u32, 37 x: u32,
38 y: u32, 38 y: u32,
@@ -108,16 +108,16 @@ fn doctest_add_impl() {
108 "add_impl", 108 "add_impl",
109 r#####" 109 r#####"
110struct Ctx<T: Clone> { 110struct Ctx<T: Clone> {
111 data: T,<|> 111 data: T,<|>
112} 112}
113"#####, 113"#####,
114 r#####" 114 r#####"
115struct Ctx<T: Clone> { 115struct Ctx<T: Clone> {
116 data: T, 116 data: T,
117} 117}
118 118
119impl<T: Clone> Ctx<T> { 119impl<T: Clone> Ctx<T> {
120 120 $0
121} 121}
122"#####, 122"#####,
123 ) 123 )