diff options
-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 | ||||
-rw-r--r-- | crates/ra_ide/src/assists.rs | 42 | ||||
-rw-r--r-- | crates/ra_ide/src/lib.rs | 31 | ||||
-rw-r--r-- | crates/ra_ide_db/src/source_change.rs | 6 |
6 files changed, 60 insertions, 87 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); |
diff --git a/crates/ra_ide/src/assists.rs b/crates/ra_ide/src/assists.rs deleted file mode 100644 index 389339a03..000000000 --- a/crates/ra_ide/src/assists.rs +++ /dev/null | |||
@@ -1,42 +0,0 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use ra_assists::{resolved_assists, AssistAction}; | ||
4 | use ra_db::{FilePosition, FileRange}; | ||
5 | use ra_ide_db::RootDatabase; | ||
6 | |||
7 | use crate::{FileId, SourceChange, SourceFileEdit}; | ||
8 | |||
9 | pub use ra_assists::AssistId; | ||
10 | |||
11 | #[derive(Debug)] | ||
12 | pub struct Assist { | ||
13 | pub id: AssistId, | ||
14 | pub label: String, | ||
15 | pub group_label: Option<String>, | ||
16 | pub source_change: SourceChange, | ||
17 | } | ||
18 | |||
19 | pub(crate) fn assists(db: &RootDatabase, frange: FileRange) -> Vec<Assist> { | ||
20 | resolved_assists(db, frange) | ||
21 | .into_iter() | ||
22 | .map(|assist| { | ||
23 | let file_id = frange.file_id; | ||
24 | Assist { | ||
25 | id: assist.label.id, | ||
26 | label: assist.label.label.clone(), | ||
27 | group_label: assist.label.group.map(|it| it.0), | ||
28 | source_change: action_to_edit(assist.action, file_id, assist.label.label.clone()), | ||
29 | } | ||
30 | }) | ||
31 | .collect() | ||
32 | } | ||
33 | |||
34 | fn action_to_edit(action: AssistAction, file_id: FileId, label: String) -> SourceChange { | ||
35 | let file_id = match action.file { | ||
36 | ra_assists::AssistFile::TargetFile(it) => it, | ||
37 | _ => file_id, | ||
38 | }; | ||
39 | let file_edit = SourceFileEdit { file_id, edit: action.edit }; | ||
40 | SourceChange::source_file_edit(label, file_edit) | ||
41 | .with_cursor_opt(action.cursor_position.map(|offset| FilePosition { offset, file_id })) | ||
42 | } | ||
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs index 4ed02f60e..614029de4 100644 --- a/crates/ra_ide/src/lib.rs +++ b/crates/ra_ide/src/lib.rs | |||
@@ -31,7 +31,6 @@ mod syntax_highlighting; | |||
31 | mod parent_module; | 31 | mod parent_module; |
32 | mod references; | 32 | mod references; |
33 | mod impls; | 33 | mod impls; |
34 | mod assists; | ||
35 | mod diagnostics; | 34 | mod diagnostics; |
36 | mod syntax_tree; | 35 | mod syntax_tree; |
37 | mod folding_ranges; | 36 | mod folding_ranges; |
@@ -64,7 +63,6 @@ use ra_syntax::{SourceFile, TextRange, TextSize}; | |||
64 | use crate::display::ToNav; | 63 | use crate::display::ToNav; |
65 | 64 | ||
66 | pub use crate::{ | 65 | pub use crate::{ |
67 | assists::{Assist, AssistId}, | ||
68 | call_hierarchy::CallItem, | 66 | call_hierarchy::CallItem, |
69 | completion::{ | 67 | completion::{ |
70 | CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat, | 68 | CompletionConfig, CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat, |
@@ -84,6 +82,7 @@ pub use crate::{ | |||
84 | }; | 82 | }; |
85 | 83 | ||
86 | pub use hir::Documentation; | 84 | pub use hir::Documentation; |
85 | pub use ra_assists::AssistId; | ||
87 | pub use ra_db::{ | 86 | pub use ra_db::{ |
88 | Canceled, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, SourceRootId, | 87 | Canceled, CrateGraph, CrateId, Edition, FileId, FilePosition, FileRange, SourceRootId, |
89 | }; | 88 | }; |
@@ -134,10 +133,12 @@ pub struct AnalysisHost { | |||
134 | db: RootDatabase, | 133 | db: RootDatabase, |
135 | } | 134 | } |
136 | 135 | ||
137 | impl Default for AnalysisHost { | 136 | #[derive(Debug)] |
138 | fn default() -> AnalysisHost { | 137 | pub struct Assist { |
139 | AnalysisHost::new(None) | 138 | pub id: AssistId, |
140 | } | 139 | pub label: String, |
140 | pub group_label: Option<String>, | ||
141 | pub source_change: SourceChange, | ||
141 | } | 142 | } |
142 | 143 | ||
143 | impl AnalysisHost { | 144 | impl AnalysisHost { |
@@ -187,6 +188,12 @@ impl AnalysisHost { | |||
187 | } | 188 | } |
188 | } | 189 | } |
189 | 190 | ||
191 | impl Default for AnalysisHost { | ||
192 | fn default() -> AnalysisHost { | ||
193 | AnalysisHost::new(None) | ||
194 | } | ||
195 | } | ||
196 | |||
190 | /// Analysis is a snapshot of a world state at a moment in time. It is the main | 197 | /// Analysis is a snapshot of a world state at a moment in time. It is the main |
191 | /// entry point for asking semantic information about the world. When the world | 198 | /// entry point for asking semantic information about the world. When the world |
192 | /// state is advanced using `AnalysisHost::apply_change` method, all existing | 199 | /// state is advanced using `AnalysisHost::apply_change` method, all existing |
@@ -464,7 +471,17 @@ impl Analysis { | |||
464 | /// Computes assists (aka code actions aka intentions) for the given | 471 | /// Computes assists (aka code actions aka intentions) for the given |
465 | /// position. | 472 | /// position. |
466 | pub fn assists(&self, frange: FileRange) -> Cancelable<Vec<Assist>> { | 473 | pub fn assists(&self, frange: FileRange) -> Cancelable<Vec<Assist>> { |
467 | self.with_db(|db| assists::assists(db, frange)) | 474 | self.with_db(|db| { |
475 | ra_assists::resolved_assists(db, frange) | ||
476 | .into_iter() | ||
477 | .map(|assist| Assist { | ||
478 | id: assist.label.id, | ||
479 | label: assist.label.label, | ||
480 | group_label: assist.label.group.map(|it| it.0), | ||
481 | source_change: assist.action, | ||
482 | }) | ||
483 | .collect() | ||
484 | }) | ||
468 | } | 485 | } |
469 | 486 | ||
470 | /// Computes the set of diagnostics for the given file. | 487 | /// Computes the set of diagnostics for the given file. |
diff --git a/crates/ra_ide_db/src/source_change.rs b/crates/ra_ide_db/src/source_change.rs index 4dd01b312..af81a91a4 100644 --- a/crates/ra_ide_db/src/source_change.rs +++ b/crates/ra_ide_db/src/source_change.rs | |||
@@ -6,7 +6,7 @@ | |||
6 | use ra_db::{FileId, FilePosition, RelativePathBuf, SourceRootId}; | 6 | use ra_db::{FileId, FilePosition, RelativePathBuf, SourceRootId}; |
7 | use ra_text_edit::{TextEdit, TextSize}; | 7 | use ra_text_edit::{TextEdit, TextSize}; |
8 | 8 | ||
9 | #[derive(Debug)] | 9 | #[derive(Debug, Clone)] |
10 | pub struct SourceChange { | 10 | pub struct SourceChange { |
11 | /// For display in the undo log in the editor | 11 | /// For display in the undo log in the editor |
12 | pub label: String, | 12 | pub label: String, |
@@ -90,13 +90,13 @@ impl SourceChange { | |||
90 | } | 90 | } |
91 | } | 91 | } |
92 | 92 | ||
93 | #[derive(Debug)] | 93 | #[derive(Debug, Clone)] |
94 | pub struct SourceFileEdit { | 94 | pub struct SourceFileEdit { |
95 | pub file_id: FileId, | 95 | pub file_id: FileId, |
96 | pub edit: TextEdit, | 96 | pub edit: TextEdit, |
97 | } | 97 | } |
98 | 98 | ||
99 | #[derive(Debug)] | 99 | #[derive(Debug, Clone)] |
100 | pub enum FileSystemEdit { | 100 | pub enum FileSystemEdit { |
101 | CreateFile { source_root: SourceRootId, path: RelativePathBuf }, | 101 | CreateFile { source_root: SourceRootId, path: RelativePathBuf }, |
102 | MoveFile { src: FileId, dst_source_root: SourceRootId, dst_path: RelativePathBuf }, | 102 | MoveFile { src: FileId, dst_source_root: SourceRootId, dst_path: RelativePathBuf }, |