diff options
Diffstat (limited to 'crates/ra_assists')
-rw-r--r-- | crates/ra_assists/src/assist_config.rs | 27 | ||||
-rw-r--r-- | crates/ra_assists/src/assist_context.rs | 41 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/add_custom_impl.rs | 51 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/add_derive.rs | 28 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/add_impl.rs | 34 | ||||
-rw-r--r-- | crates/ra_assists/src/lib.rs | 15 | ||||
-rw-r--r-- | crates/ra_assists/src/tests.rs | 38 | ||||
-rw-r--r-- | crates/ra_assists/src/tests/generated.rs | 10 |
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)] | ||
8 | pub struct AssistConfig { | ||
9 | pub snippet_cap: Option<SnippetCap>, | ||
10 | } | ||
11 | |||
12 | impl 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)] | ||
19 | pub struct SnippetCap { | ||
20 | _private: (), | ||
21 | } | ||
22 | |||
23 | impl 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 | }; |
16 | use ra_text_edit::TextEditBuilder; | 16 | use ra_text_edit::TextEditBuilder; |
17 | 17 | ||
18 | use crate::{Assist, AssistId, GroupLabel, ResolvedAssist}; | 18 | use 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 :-) |
50 | pub(crate) struct AssistContext<'a> { | 53 | pub(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 | ||
57 | impl<'a> AssistContext<'a> { | 61 | impl<'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 | ||
170 | impl AssistBuilder { | 179 | impl 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 | // ``` |
31 | pub(crate) fn add_custom_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 31 | pub(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 | ||
119 | impl Debug for Foo { | 120 | impl Debug for Foo { |
120 | <|> | 121 | $0 |
121 | } | 122 | } |
122 | ", | 123 | ", |
123 | ) | 124 | ) |
@@ -139,7 +140,7 @@ pub struct Foo { | |||
139 | } | 140 | } |
140 | 141 | ||
141 | impl Debug for Foo { | 142 | impl Debug for Foo { |
142 | <|> | 143 | $0 |
143 | } | 144 | } |
144 | ", | 145 | ", |
145 | ) | 146 | ) |
@@ -158,7 +159,7 @@ struct Foo {} | |||
158 | struct Foo {} | 159 | struct Foo {} |
159 | 160 | ||
160 | impl Debug for Foo { | 161 | impl 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 | // ``` |
27 | pub(crate) fn add_derive(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 27 | pub(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)] |
100 | struct Foo { a: i32, } | 106 | struct 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 @@ | |||
1 | use ra_syntax::{ | 1 | use ra_syntax::ast::{self, AstNode, NameOwner, TypeParamsOwner}; |
2 | ast::{self, AstNode, NameOwner, TypeParamsOwner}, | ||
3 | TextSize, | ||
4 | }; | ||
5 | use stdx::{format_to, SepBy}; | 2 | use stdx::{format_to, SepBy}; |
6 | 3 | ||
7 | use crate::{AssistContext, AssistId, Assists}; | 4 | use 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 | // ``` |
28 | pub(crate) fn add_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 25 | pub(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)] |
61 | mod tests { | 64 | mod 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 | ||
13 | mod assist_config; | ||
13 | mod assist_context; | 14 | mod assist_context; |
14 | mod marks; | 15 | mod marks; |
15 | #[cfg(test)] | 16 | #[cfg(test)] |
@@ -24,6 +25,8 @@ use ra_syntax::TextRange; | |||
24 | 25 | ||
25 | pub(crate) use crate::assist_context::{AssistContext, Assists}; | 26 | pub(crate) use crate::assist_context::{AssistContext, Assists}; |
26 | 27 | ||
28 | pub 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 | ||
14 | use crate::{handlers::Handler, Assist, AssistContext, Assists}; | 14 | use crate::{handlers::Handler, Assist, AssistConfig, AssistContext, Assists}; |
15 | 15 | ||
16 | pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) { | 16 | pub(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; | |||
15 | struct S; | 15 | struct S; |
16 | 16 | ||
17 | impl Debug for S { | 17 | impl 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)] |
36 | struct Point { | 36 | struct 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#####" |
110 | struct Ctx<T: Clone> { | 110 | struct Ctx<T: Clone> { |
111 | data: T,<|> | 111 | data: T,<|> |
112 | } | 112 | } |
113 | "#####, | 113 | "#####, |
114 | r#####" | 114 | r#####" |
115 | struct Ctx<T: Clone> { | 115 | struct Ctx<T: Clone> { |
116 | data: T, | 116 | data: T, |
117 | } | 117 | } |
118 | 118 | ||
119 | impl<T: Clone> Ctx<T> { | 119 | impl<T: Clone> Ctx<T> { |
120 | 120 | $0 | |
121 | } | 121 | } |
122 | "#####, | 122 | "#####, |
123 | ) | 123 | ) |