diff options
Diffstat (limited to 'crates/ra_assists')
-rw-r--r-- | crates/ra_assists/src/assist_ctx.rs | 30 | ||||
-rw-r--r-- | crates/ra_assists/src/lib.rs | 16 | ||||
-rw-r--r-- | crates/ra_assists/src/tests.rs | 22 |
3 files changed, 33 insertions, 35 deletions
diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs index cbf1963b7..77275156c 100644 --- a/crates/ra_assists/src/assist_ctx.rs +++ b/crates/ra_assists/src/assist_ctx.rs | |||
@@ -1,8 +1,11 @@ | |||
1 | //! This module defines `AssistCtx` -- the API surface that is exposed to assists. | 1 | //! This module defines `AssistCtx` -- the API surface that is exposed to assists. |
2 | use hir::Semantics; | 2 | use hir::Semantics; |
3 | use ra_db::FileRange; | 3 | use ra_db::{FileId, FileRange}; |
4 | use ra_fmt::{leading_indent, reindent}; | 4 | use ra_fmt::{leading_indent, reindent}; |
5 | use ra_ide_db::RootDatabase; | 5 | use ra_ide_db::{ |
6 | source_change::{SingleFileChange, SourceChange}, | ||
7 | RootDatabase, | ||
8 | }; | ||
6 | use ra_syntax::{ | 9 | use ra_syntax::{ |
7 | algo::{self, find_covering_element, find_node_at_offset, SyntaxRewriter}, | 10 | algo::{self, find_covering_element, find_node_at_offset, SyntaxRewriter}, |
8 | AstNode, SourceFile, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, TextSize, | 11 | AstNode, SourceFile, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange, TextSize, |
@@ -10,7 +13,7 @@ use ra_syntax::{ | |||
10 | }; | 13 | }; |
11 | use ra_text_edit::TextEditBuilder; | 14 | use ra_text_edit::TextEditBuilder; |
12 | 15 | ||
13 | use crate::{AssistAction, AssistFile, AssistId, AssistLabel, GroupLabel, ResolvedAssist}; | 16 | use crate::{AssistFile, AssistId, AssistLabel, GroupLabel, ResolvedAssist}; |
14 | 17 | ||
15 | #[derive(Clone, Debug)] | 18 | #[derive(Clone, Debug)] |
16 | pub(crate) struct Assist(pub(crate) Vec<AssistInfo>); | 19 | pub(crate) struct Assist(pub(crate) Vec<AssistInfo>); |
@@ -19,7 +22,7 @@ pub(crate) struct Assist(pub(crate) Vec<AssistInfo>); | |||
19 | pub(crate) struct AssistInfo { | 22 | pub(crate) struct AssistInfo { |
20 | pub(crate) label: AssistLabel, | 23 | pub(crate) label: AssistLabel, |
21 | pub(crate) group_label: Option<GroupLabel>, | 24 | pub(crate) group_label: Option<GroupLabel>, |
22 | pub(crate) action: Option<AssistAction>, | 25 | pub(crate) action: Option<SourceChange>, |
23 | } | 26 | } |
24 | 27 | ||
25 | impl AssistInfo { | 28 | impl AssistInfo { |
@@ -27,7 +30,7 @@ impl AssistInfo { | |||
27 | AssistInfo { label, group_label: None, action: None } | 30 | AssistInfo { label, group_label: None, action: None } |
28 | } | 31 | } |
29 | 32 | ||
30 | fn resolved(self, action: AssistAction) -> AssistInfo { | 33 | fn resolved(self, action: SourceChange) -> AssistInfo { |
31 | AssistInfo { action: Some(action), ..self } | 34 | AssistInfo { action: Some(action), ..self } |
32 | } | 35 | } |
33 | 36 | ||
@@ -98,13 +101,13 @@ impl<'a> AssistCtx<'a> { | |||
98 | f: impl FnOnce(&mut ActionBuilder), | 101 | f: impl FnOnce(&mut ActionBuilder), |
99 | ) -> Option<Assist> { | 102 | ) -> Option<Assist> { |
100 | let label = AssistLabel::new(id, label.into(), None, target); | 103 | let label = AssistLabel::new(id, label.into(), None, target); |
101 | 104 | let change_label = label.label.clone(); | |
102 | let mut info = AssistInfo::new(label); | 105 | let mut info = AssistInfo::new(label); |
103 | if self.should_compute_edit { | 106 | if self.should_compute_edit { |
104 | let action = { | 107 | let action = { |
105 | let mut edit = ActionBuilder::new(&self); | 108 | let mut edit = ActionBuilder::new(&self); |
106 | f(&mut edit); | 109 | f(&mut edit); |
107 | edit.build() | 110 | edit.build(change_label, self.frange.file_id) |
108 | }; | 111 | }; |
109 | info = info.resolved(action) | 112 | info = info.resolved(action) |
110 | }; | 113 | }; |
@@ -157,13 +160,13 @@ impl<'a> AssistGroup<'a> { | |||
157 | f: impl FnOnce(&mut ActionBuilder), | 160 | f: impl FnOnce(&mut ActionBuilder), |
158 | ) { | 161 | ) { |
159 | let label = AssistLabel::new(id, label.into(), Some(self.group.clone()), target); | 162 | let label = AssistLabel::new(id, label.into(), Some(self.group.clone()), target); |
160 | 163 | let change_label = label.label.clone(); | |
161 | let mut info = AssistInfo::new(label).with_group(self.group.clone()); | 164 | let mut info = AssistInfo::new(label).with_group(self.group.clone()); |
162 | if self.ctx.should_compute_edit { | 165 | if self.ctx.should_compute_edit { |
163 | let action = { | 166 | let action = { |
164 | let mut edit = ActionBuilder::new(&self.ctx); | 167 | let mut edit = ActionBuilder::new(&self.ctx); |
165 | f(&mut edit); | 168 | f(&mut edit); |
166 | edit.build() | 169 | edit.build(change_label, self.ctx.frange.file_id) |
167 | }; | 170 | }; |
168 | info = info.resolved(action) | 171 | info = info.resolved(action) |
169 | }; | 172 | }; |
@@ -255,11 +258,16 @@ impl<'a, 'b> ActionBuilder<'a, 'b> { | |||
255 | self.file = assist_file | 258 | self.file = assist_file |
256 | } | 259 | } |
257 | 260 | ||
258 | fn build(self) -> AssistAction { | 261 | fn build(self, change_label: String, current_file: FileId) -> SourceChange { |
259 | let edit = self.edit.finish(); | 262 | let edit = self.edit.finish(); |
260 | if edit.is_empty() && self.cursor_position.is_none() { | 263 | if edit.is_empty() && self.cursor_position.is_none() { |
261 | panic!("Only call `add_assist` if the assist can be applied") | 264 | panic!("Only call `add_assist` if the assist can be applied") |
262 | } | 265 | } |
263 | AssistAction { edit, cursor_position: self.cursor_position, file: self.file } | 266 | let file = match self.file { |
267 | AssistFile::CurrentFile => current_file, | ||
268 | AssistFile::TargetFile(it) => it, | ||
269 | }; | ||
270 | SingleFileChange { label: change_label, edit, cursor_position: self.cursor_position } | ||
271 | .into_source_change(file) | ||
264 | } | 272 | } |
265 | } | 273 | } |
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index f4f37614f..8cd8f89c4 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs | |||
@@ -19,9 +19,8 @@ pub mod ast_transform; | |||
19 | 19 | ||
20 | use hir::Semantics; | 20 | use hir::Semantics; |
21 | use ra_db::{FileId, FileRange}; | 21 | use ra_db::{FileId, FileRange}; |
22 | use ra_ide_db::RootDatabase; | 22 | use ra_ide_db::{source_change::SourceChange, RootDatabase}; |
23 | use ra_syntax::{TextRange, TextSize}; | 23 | use ra_syntax::TextRange; |
24 | use ra_text_edit::TextEdit; | ||
25 | 24 | ||
26 | pub(crate) use crate::assist_ctx::{Assist, AssistCtx}; | 25 | pub(crate) use crate::assist_ctx::{Assist, AssistCtx}; |
27 | 26 | ||
@@ -58,20 +57,13 @@ impl AssistLabel { | |||
58 | } | 57 | } |
59 | 58 | ||
60 | #[derive(Debug, Clone)] | 59 | #[derive(Debug, Clone)] |
61 | pub struct AssistAction { | ||
62 | pub edit: TextEdit, | ||
63 | pub cursor_position: Option<TextSize>, | ||
64 | pub file: AssistFile, | ||
65 | } | ||
66 | |||
67 | #[derive(Debug, Clone)] | ||
68 | pub struct ResolvedAssist { | 60 | pub struct ResolvedAssist { |
69 | pub label: AssistLabel, | 61 | pub label: AssistLabel, |
70 | pub action: AssistAction, | 62 | pub action: SourceChange, |
71 | } | 63 | } |
72 | 64 | ||
73 | #[derive(Debug, Clone, Copy)] | 65 | #[derive(Debug, Clone, Copy)] |
74 | pub enum AssistFile { | 66 | enum AssistFile { |
75 | CurrentFile, | 67 | CurrentFile, |
76 | TargetFile(FileId), | 68 | TargetFile(FileId), |
77 | } | 69 | } |
diff --git a/crates/ra_assists/src/tests.rs b/crates/ra_assists/src/tests.rs index dd9026df6..572462bfc 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, resolved_assists, AssistCtx, AssistFile}; | 14 | use crate::{handlers::Handler, resolved_assists, AssistCtx}; |
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,7 +41,7 @@ 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 assist = resolved_assists(&db, frange) | 44 | let mut assist = resolved_assists(&db, frange) |
45 | .into_iter() | 45 | .into_iter() |
46 | .find(|assist| assist.label.id.0 == assist_id) | 46 | .find(|assist| assist.label.id.0 == assist_id) |
47 | .unwrap_or_else(|| { | 47 | .unwrap_or_else(|| { |
@@ -57,8 +57,9 @@ fn check_doc_test(assist_id: &str, before: &str, after: &str) { | |||
57 | }); | 57 | }); |
58 | 58 | ||
59 | let actual = { | 59 | let actual = { |
60 | let change = assist.action.source_file_edits.pop().unwrap(); | ||
60 | let mut actual = before.clone(); | 61 | let mut actual = before.clone(); |
61 | assist.action.edit.apply(&mut actual); | 62 | change.edit.apply(&mut actual); |
62 | actual | 63 | actual |
63 | }; | 64 | }; |
64 | assert_eq_text!(after, &actual); | 65 | assert_eq_text!(after, &actual); |
@@ -93,26 +94,23 @@ fn check(assist: Handler, before: &str, expected: ExpectedResult) { | |||
93 | 94 | ||
94 | match (assist(assist_ctx), expected) { | 95 | match (assist(assist_ctx), expected) { |
95 | (Some(assist), ExpectedResult::After(after)) => { | 96 | (Some(assist), ExpectedResult::After(after)) => { |
96 | let action = assist.0[0].action.clone().unwrap(); | 97 | let mut action = assist.0[0].action.clone().unwrap(); |
98 | let change = action.source_file_edits.pop().unwrap(); | ||
97 | 99 | ||
98 | let mut actual = if let AssistFile::TargetFile(file_id) = action.file { | 100 | let mut actual = db.file_text(change.file_id).as_ref().to_owned(); |
99 | db.file_text(file_id).as_ref().to_owned() | 101 | change.edit.apply(&mut actual); |
100 | } else { | ||
101 | text_without_caret | ||
102 | }; | ||
103 | action.edit.apply(&mut actual); | ||
104 | 102 | ||
105 | match action.cursor_position { | 103 | match action.cursor_position { |
106 | None => { | 104 | None => { |
107 | if let RangeOrOffset::Offset(before_cursor_pos) = range_or_offset { | 105 | if let RangeOrOffset::Offset(before_cursor_pos) = range_or_offset { |
108 | let off = action | 106 | let off = change |
109 | .edit | 107 | .edit |
110 | .apply_to_offset(before_cursor_pos) | 108 | .apply_to_offset(before_cursor_pos) |
111 | .expect("cursor position is affected by the edit"); | 109 | .expect("cursor position is affected by the edit"); |
112 | actual = add_cursor(&actual, off) | 110 | actual = add_cursor(&actual, off) |
113 | } | 111 | } |
114 | } | 112 | } |
115 | Some(off) => actual = add_cursor(&actual, off), | 113 | Some(off) => actual = add_cursor(&actual, off.offset), |
116 | }; | 114 | }; |
117 | 115 | ||
118 | assert_eq_text!(after, &actual); | 116 | assert_eq_text!(after, &actual); |