aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_assists/src/assist_ctx.rs30
-rw-r--r--crates/ra_assists/src/lib.rs16
-rw-r--r--crates/ra_assists/src/tests.rs22
-rw-r--r--crates/ra_ide/src/assists.rs42
-rw-r--r--crates/ra_ide/src/lib.rs31
-rw-r--r--crates/ra_ide_db/src/source_change.rs6
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.
2use hir::Semantics; 2use hir::Semantics;
3use ra_db::FileRange; 3use ra_db::{FileId, FileRange};
4use ra_fmt::{leading_indent, reindent}; 4use ra_fmt::{leading_indent, reindent};
5use ra_ide_db::RootDatabase; 5use ra_ide_db::{
6 source_change::{SingleFileChange, SourceChange},
7 RootDatabase,
8};
6use ra_syntax::{ 9use 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};
11use ra_text_edit::TextEditBuilder; 14use ra_text_edit::TextEditBuilder;
12 15
13use crate::{AssistAction, AssistFile, AssistId, AssistLabel, GroupLabel, ResolvedAssist}; 16use crate::{AssistFile, AssistId, AssistLabel, GroupLabel, ResolvedAssist};
14 17
15#[derive(Clone, Debug)] 18#[derive(Clone, Debug)]
16pub(crate) struct Assist(pub(crate) Vec<AssistInfo>); 19pub(crate) struct Assist(pub(crate) Vec<AssistInfo>);
@@ -19,7 +22,7 @@ pub(crate) struct Assist(pub(crate) Vec<AssistInfo>);
19pub(crate) struct AssistInfo { 22pub(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
25impl AssistInfo { 28impl 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
20use hir::Semantics; 20use hir::Semantics;
21use ra_db::{FileId, FileRange}; 21use ra_db::{FileId, FileRange};
22use ra_ide_db::RootDatabase; 22use ra_ide_db::{source_change::SourceChange, RootDatabase};
23use ra_syntax::{TextRange, TextSize}; 23use ra_syntax::TextRange;
24use ra_text_edit::TextEdit;
25 24
26pub(crate) use crate::assist_ctx::{Assist, AssistCtx}; 25pub(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)]
61pub struct AssistAction {
62 pub edit: TextEdit,
63 pub cursor_position: Option<TextSize>,
64 pub file: AssistFile,
65}
66
67#[derive(Debug, Clone)]
68pub struct ResolvedAssist { 60pub 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)]
74pub enum AssistFile { 66enum 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
14use crate::{handlers::Handler, resolved_assists, AssistCtx, AssistFile}; 14use crate::{handlers::Handler, resolved_assists, AssistCtx};
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,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
3use ra_assists::{resolved_assists, AssistAction};
4use ra_db::{FilePosition, FileRange};
5use ra_ide_db::RootDatabase;
6
7use crate::{FileId, SourceChange, SourceFileEdit};
8
9pub use ra_assists::AssistId;
10
11#[derive(Debug)]
12pub struct Assist {
13 pub id: AssistId,
14 pub label: String,
15 pub group_label: Option<String>,
16 pub source_change: SourceChange,
17}
18
19pub(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
34fn 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;
31mod parent_module; 31mod parent_module;
32mod references; 32mod references;
33mod impls; 33mod impls;
34mod assists;
35mod diagnostics; 34mod diagnostics;
36mod syntax_tree; 35mod syntax_tree;
37mod folding_ranges; 36mod folding_ranges;
@@ -64,7 +63,6 @@ use ra_syntax::{SourceFile, TextRange, TextSize};
64use crate::display::ToNav; 63use crate::display::ToNav;
65 64
66pub use crate::{ 65pub 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
86pub use hir::Documentation; 84pub use hir::Documentation;
85pub use ra_assists::AssistId;
87pub use ra_db::{ 86pub 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
137impl Default for AnalysisHost { 136#[derive(Debug)]
138 fn default() -> AnalysisHost { 137pub 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
143impl AnalysisHost { 144impl AnalysisHost {
@@ -187,6 +188,12 @@ impl AnalysisHost {
187 } 188 }
188} 189}
189 190
191impl 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 @@
6use ra_db::{FileId, FilePosition, RelativePathBuf, SourceRootId}; 6use ra_db::{FileId, FilePosition, RelativePathBuf, SourceRootId};
7use ra_text_edit::{TextEdit, TextSize}; 7use ra_text_edit::{TextEdit, TextSize};
8 8
9#[derive(Debug)] 9#[derive(Debug, Clone)]
10pub struct SourceChange { 10pub 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)]
94pub struct SourceFileEdit { 94pub 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)]
100pub enum FileSystemEdit { 100pub 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 },