diff options
author | Kirill Bulatov <[email protected]> | 2020-01-11 22:40:36 +0000 |
---|---|---|
committer | Kirill Bulatov <[email protected]> | 2020-01-15 18:17:17 +0000 |
commit | 78a21253b494e573885ac8336bff6e93b401046f (patch) | |
tree | 3ec31f8481f9a930b0b3afb6cc0ce4c97cf648f2 /crates | |
parent | 73dc8b6f06b49f4728a50e83781c361e9a8b3100 (diff) |
Apply the api design suggestions
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_assists/src/assist_ctx.rs | 25 | ||||
-rw-r--r-- | crates/ra_assists/src/doc_tests.rs | 8 | ||||
-rw-r--r-- | crates/ra_assists/src/lib.rs | 40 | ||||
-rw-r--r-- | crates/ra_ide/src/assists.rs | 23 | ||||
-rw-r--r-- | crates/ra_lsp_server/Cargo.toml | 1 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main_loop/handlers.rs | 28 |
6 files changed, 79 insertions, 46 deletions
diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs index 879216a36..e13f969c7 100644 --- a/crates/ra_assists/src/assist_ctx.rs +++ b/crates/ra_assists/src/assist_ctx.rs | |||
@@ -1,5 +1,6 @@ | |||
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::{db::HirDatabase, InFile, SourceAnalyzer}; | 2 | use hir::{db::HirDatabase, InFile, SourceAnalyzer}; |
3 | use itertools::Either; | ||
3 | use ra_db::FileRange; | 4 | use ra_db::FileRange; |
4 | use ra_fmt::{leading_indent, reindent}; | 5 | use ra_fmt::{leading_indent, reindent}; |
5 | use ra_syntax::{ | 6 | use ra_syntax::{ |
@@ -9,12 +10,12 @@ use ra_syntax::{ | |||
9 | }; | 10 | }; |
10 | use ra_text_edit::TextEditBuilder; | 11 | use ra_text_edit::TextEditBuilder; |
11 | 12 | ||
12 | use crate::{AssistAction, AssistId, AssistLabel}; | 13 | use crate::{AssistAction, AssistId, AssistLabel, ResolvedAssist}; |
13 | 14 | ||
14 | #[derive(Clone, Debug)] | 15 | #[derive(Clone, Debug)] |
15 | pub(crate) enum Assist { | 16 | pub(crate) enum Assist { |
16 | Unresolved { label: AssistLabel }, | 17 | Unresolved { label: AssistLabel }, |
17 | Resolved { label: AssistLabel, action: AssistAction, alternative_actions: Vec<AssistAction> }, | 18 | Resolved { assist: ResolvedAssist }, |
18 | } | 19 | } |
19 | 20 | ||
20 | /// `AssistCtx` allows to apply an assist or check if it could be applied. | 21 | /// `AssistCtx` allows to apply an assist or check if it could be applied. |
@@ -92,7 +93,7 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> { | |||
92 | f(&mut edit); | 93 | f(&mut edit); |
93 | edit.build() | 94 | edit.build() |
94 | }; | 95 | }; |
95 | Assist::Resolved { label, action, alternative_actions: Vec::default() } | 96 | Assist::Resolved { assist: ResolvedAssist { label, action_data: Either::Left(action) } } |
96 | } else { | 97 | } else { |
97 | Assist::Unresolved { label } | 98 | Assist::Unresolved { label } |
98 | }; | 99 | }; |
@@ -105,18 +106,20 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> { | |||
105 | self, | 106 | self, |
106 | id: AssistId, | 107 | id: AssistId, |
107 | label: impl Into<String>, | 108 | label: impl Into<String>, |
108 | f: impl FnOnce() -> (ActionBuilder, Vec<ActionBuilder>), | 109 | f: impl FnOnce() -> Vec<ActionBuilder>, |
109 | ) -> Option<Assist> { | 110 | ) -> Option<Assist> { |
110 | let label = AssistLabel { label: label.into(), id }; | 111 | let label = AssistLabel { label: label.into(), id }; |
111 | let assist = if self.should_compute_edit { | 112 | let assist = if self.should_compute_edit { |
112 | let (action, alternative_actions) = f(); | 113 | let actions = f(); |
114 | assert!(!actions.is_empty(), "Assist cannot have no"); | ||
115 | |||
113 | Assist::Resolved { | 116 | Assist::Resolved { |
114 | label, | 117 | assist: ResolvedAssist { |
115 | action: action.build(), | 118 | label, |
116 | alternative_actions: alternative_actions | 119 | action_data: Either::Right( |
117 | .into_iter() | 120 | actions.into_iter().map(ActionBuilder::build).collect(), |
118 | .map(ActionBuilder::build) | 121 | ), |
119 | .collect(), | 122 | }, |
120 | } | 123 | } |
121 | } else { | 124 | } else { |
122 | Assist::Unresolved { label } | 125 | Assist::Unresolved { label } |
diff --git a/crates/ra_assists/src/doc_tests.rs b/crates/ra_assists/src/doc_tests.rs index 21bee228d..5dc1ee233 100644 --- a/crates/ra_assists/src/doc_tests.rs +++ b/crates/ra_assists/src/doc_tests.rs | |||
@@ -15,21 +15,21 @@ fn check(assist_id: &str, before: &str, after: &str) { | |||
15 | let (db, file_id) = TestDB::with_single_file(&before); | 15 | let (db, file_id) = TestDB::with_single_file(&before); |
16 | let frange = FileRange { file_id, range: selection.into() }; | 16 | let frange = FileRange { file_id, range: selection.into() }; |
17 | 17 | ||
18 | let (_assist_id, action, _) = crate::assists(&db, frange) | 18 | let assist = crate::assists(&db, frange) |
19 | .into_iter() | 19 | .into_iter() |
20 | .find(|(id, _, _)| id.id.0 == assist_id) | 20 | .find(|assist| assist.label.id.0 == assist_id) |
21 | .unwrap_or_else(|| { | 21 | .unwrap_or_else(|| { |
22 | panic!( | 22 | panic!( |
23 | "\n\nAssist is not applicable: {}\nAvailable assists: {}", | 23 | "\n\nAssist is not applicable: {}\nAvailable assists: {}", |
24 | assist_id, | 24 | assist_id, |
25 | crate::assists(&db, frange) | 25 | crate::assists(&db, frange) |
26 | .into_iter() | 26 | .into_iter() |
27 | .map(|(id, _, _)| id.id.0) | 27 | .map(|assist| assist.label.id.0) |
28 | .collect::<Vec<_>>() | 28 | .collect::<Vec<_>>() |
29 | .join(", ") | 29 | .join(", ") |
30 | ) | 30 | ) |
31 | }); | 31 | }); |
32 | 32 | ||
33 | let actual = action.edit.apply(&before); | 33 | let actual = assist.get_first_action().edit.apply(&before); |
34 | assert_eq_text!(after, &actual); | 34 | assert_eq_text!(after, &actual); |
35 | } | 35 | } |
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index 95a530821..a2983ae87 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs | |||
@@ -14,6 +14,7 @@ mod test_db; | |||
14 | pub mod ast_transform; | 14 | pub mod ast_transform; |
15 | 15 | ||
16 | use hir::db::HirDatabase; | 16 | use hir::db::HirDatabase; |
17 | use itertools::Either; | ||
17 | use ra_db::FileRange; | 18 | use ra_db::FileRange; |
18 | use ra_syntax::{TextRange, TextUnit}; | 19 | use ra_syntax::{TextRange, TextUnit}; |
19 | use ra_text_edit::TextEdit; | 20 | use ra_text_edit::TextEdit; |
@@ -41,6 +42,21 @@ pub struct AssistAction { | |||
41 | pub target: Option<TextRange>, | 42 | pub target: Option<TextRange>, |
42 | } | 43 | } |
43 | 44 | ||
45 | #[derive(Debug, Clone)] | ||
46 | pub struct ResolvedAssist { | ||
47 | pub label: AssistLabel, | ||
48 | pub action_data: Either<AssistAction, Vec<AssistAction>>, | ||
49 | } | ||
50 | |||
51 | impl ResolvedAssist { | ||
52 | pub fn get_first_action(&self) -> AssistAction { | ||
53 | match &self.action_data { | ||
54 | Either::Left(action) => action.clone(), | ||
55 | Either::Right(actions) => actions[0].clone(), | ||
56 | } | ||
57 | } | ||
58 | } | ||
59 | |||
44 | /// Return all the assists applicable at the given position. | 60 | /// Return all the assists applicable at the given position. |
45 | /// | 61 | /// |
46 | /// Assists are returned in the "unresolved" state, that is only labels are | 62 | /// Assists are returned in the "unresolved" state, that is only labels are |
@@ -65,7 +81,7 @@ where | |||
65 | /// | 81 | /// |
66 | /// Assists are returned in the "resolved" state, that is with edit fully | 82 | /// Assists are returned in the "resolved" state, that is with edit fully |
67 | /// computed. | 83 | /// computed. |
68 | pub fn assists<H>(db: &H, range: FileRange) -> Vec<(AssistLabel, AssistAction, Vec<AssistAction>)> | 84 | pub fn assists<H>(db: &H, range: FileRange) -> Vec<ResolvedAssist> |
69 | where | 85 | where |
70 | H: HirDatabase + 'static, | 86 | H: HirDatabase + 'static, |
71 | { | 87 | { |
@@ -76,13 +92,11 @@ where | |||
76 | .iter() | 92 | .iter() |
77 | .filter_map(|f| f(ctx.clone())) | 93 | .filter_map(|f| f(ctx.clone())) |
78 | .map(|a| match a { | 94 | .map(|a| match a { |
79 | Assist::Resolved { label, action, alternative_actions } => { | 95 | Assist::Resolved { assist } => assist, |
80 | (label, action, alternative_actions) | ||
81 | } | ||
82 | Assist::Unresolved { .. } => unreachable!(), | 96 | Assist::Unresolved { .. } => unreachable!(), |
83 | }) | 97 | }) |
84 | .collect::<Vec<_>>(); | 98 | .collect::<Vec<_>>(); |
85 | a.sort_by(|a, b| match (a.1.target, b.1.target) { | 99 | a.sort_by(|a, b| match (a.get_first_action().target, b.get_first_action().target) { |
86 | (Some(a), Some(b)) => a.len().cmp(&b.len()), | 100 | (Some(a), Some(b)) => a.len().cmp(&b.len()), |
87 | (Some(_), None) => Ordering::Less, | 101 | (Some(_), None) => Ordering::Less, |
88 | (None, Some(_)) => Ordering::Greater, | 102 | (None, Some(_)) => Ordering::Greater, |
@@ -177,7 +191,7 @@ mod helpers { | |||
177 | AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); | 191 | AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); |
178 | let action = match assist { | 192 | let action = match assist { |
179 | Assist::Unresolved { .. } => unreachable!(), | 193 | Assist::Unresolved { .. } => unreachable!(), |
180 | Assist::Resolved { action, .. } => action, | 194 | Assist::Resolved { assist } => assist.get_first_action(), |
181 | }; | 195 | }; |
182 | 196 | ||
183 | let actual = action.edit.apply(&before); | 197 | let actual = action.edit.apply(&before); |
@@ -204,7 +218,7 @@ mod helpers { | |||
204 | AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); | 218 | AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); |
205 | let action = match assist { | 219 | let action = match assist { |
206 | Assist::Unresolved { .. } => unreachable!(), | 220 | Assist::Unresolved { .. } => unreachable!(), |
207 | Assist::Resolved { action, .. } => action, | 221 | Assist::Resolved { assist } => assist.get_first_action(), |
208 | }; | 222 | }; |
209 | 223 | ||
210 | let mut actual = action.edit.apply(&before); | 224 | let mut actual = action.edit.apply(&before); |
@@ -227,7 +241,7 @@ mod helpers { | |||
227 | AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); | 241 | AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); |
228 | let action = match assist { | 242 | let action = match assist { |
229 | Assist::Unresolved { .. } => unreachable!(), | 243 | Assist::Unresolved { .. } => unreachable!(), |
230 | Assist::Resolved { action, .. } => action, | 244 | Assist::Resolved { assist } => assist.get_first_action(), |
231 | }; | 245 | }; |
232 | 246 | ||
233 | let range = action.target.expect("expected target on action"); | 247 | let range = action.target.expect("expected target on action"); |
@@ -246,7 +260,7 @@ mod helpers { | |||
246 | AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); | 260 | AssistCtx::with_ctx(&db, frange, true, assist).expect("code action is not applicable"); |
247 | let action = match assist { | 261 | let action = match assist { |
248 | Assist::Unresolved { .. } => unreachable!(), | 262 | Assist::Unresolved { .. } => unreachable!(), |
249 | Assist::Resolved { action, .. } => action, | 263 | Assist::Resolved { assist } => assist.get_first_action(), |
250 | }; | 264 | }; |
251 | 265 | ||
252 | let range = action.target.expect("expected target on action"); | 266 | let range = action.target.expect("expected target on action"); |
@@ -296,10 +310,10 @@ mod tests { | |||
296 | let mut assists = assists.iter(); | 310 | let mut assists = assists.iter(); |
297 | 311 | ||
298 | assert_eq!( | 312 | assert_eq!( |
299 | assists.next().expect("expected assist").0.label, | 313 | assists.next().expect("expected assist").label.label, |
300 | "Change visibility to pub(crate)" | 314 | "Change visibility to pub(crate)" |
301 | ); | 315 | ); |
302 | assert_eq!(assists.next().expect("expected assist").0.label, "Add `#[derive]`"); | 316 | assert_eq!(assists.next().expect("expected assist").label.label, "Add `#[derive]`"); |
303 | } | 317 | } |
304 | 318 | ||
305 | #[test] | 319 | #[test] |
@@ -318,7 +332,7 @@ mod tests { | |||
318 | let assists = super::assists(&db, frange); | 332 | let assists = super::assists(&db, frange); |
319 | let mut assists = assists.iter(); | 333 | let mut assists = assists.iter(); |
320 | 334 | ||
321 | assert_eq!(assists.next().expect("expected assist").0.label, "Extract into variable"); | 335 | assert_eq!(assists.next().expect("expected assist").label.label, "Extract into variable"); |
322 | assert_eq!(assists.next().expect("expected assist").0.label, "Replace with match"); | 336 | assert_eq!(assists.next().expect("expected assist").label.label, "Replace with match"); |
323 | } | 337 | } |
324 | } | 338 | } |
diff --git a/crates/ra_ide/src/assists.rs b/crates/ra_ide/src/assists.rs index db6e4e8b7..e30eee5f4 100644 --- a/crates/ra_ide/src/assists.rs +++ b/crates/ra_ide/src/assists.rs | |||
@@ -4,30 +4,37 @@ use ra_db::{FilePosition, FileRange}; | |||
4 | 4 | ||
5 | use crate::{db::RootDatabase, FileId, SourceChange, SourceFileEdit}; | 5 | use crate::{db::RootDatabase, FileId, SourceChange, SourceFileEdit}; |
6 | 6 | ||
7 | use itertools::Either; | ||
7 | pub use ra_assists::AssistId; | 8 | pub use ra_assists::AssistId; |
8 | use ra_assists::{AssistAction, AssistLabel}; | 9 | use ra_assists::{AssistAction, AssistLabel}; |
9 | 10 | ||
10 | #[derive(Debug)] | 11 | #[derive(Debug)] |
11 | pub struct Assist { | 12 | pub struct Assist { |
12 | pub id: AssistId, | 13 | pub id: AssistId, |
13 | pub change: SourceChange, | ||
14 | pub label: String, | 14 | pub label: String, |
15 | pub alternative_changes: Vec<SourceChange>, | 15 | pub change_data: Either<SourceChange, Vec<SourceChange>>, |
16 | } | 16 | } |
17 | 17 | ||
18 | pub(crate) fn assists(db: &RootDatabase, frange: FileRange) -> Vec<Assist> { | 18 | pub(crate) fn assists(db: &RootDatabase, frange: FileRange) -> Vec<Assist> { |
19 | ra_assists::assists(db, frange) | 19 | ra_assists::assists(db, frange) |
20 | .into_iter() | 20 | .into_iter() |
21 | .map(|(assist_label, action, alternative_actions)| { | 21 | .map(|assist| { |
22 | let file_id = frange.file_id; | 22 | let file_id = frange.file_id; |
23 | let assist_label = &assist.label; | ||
23 | Assist { | 24 | Assist { |
24 | id: assist_label.id, | 25 | id: assist_label.id, |
25 | label: assist_label.label.clone(), | 26 | label: assist_label.label.clone(), |
26 | change: action_to_edit(action, file_id, &assist_label), | 27 | change_data: match assist.action_data { |
27 | alternative_changes: alternative_actions | 28 | Either::Left(action) => { |
28 | .into_iter() | 29 | Either::Left(action_to_edit(action, file_id, assist_label)) |
29 | .map(|action| action_to_edit(action, file_id, &assist_label)) | 30 | } |
30 | .collect(), | 31 | Either::Right(actions) => Either::Right( |
32 | actions | ||
33 | .into_iter() | ||
34 | .map(|action| action_to_edit(action, file_id, assist_label)) | ||
35 | .collect(), | ||
36 | ), | ||
37 | }, | ||
31 | } | 38 | } |
32 | }) | 39 | }) |
33 | .collect() | 40 | .collect() |
diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml index c08e67b8e..73bce8b08 100644 --- a/crates/ra_lsp_server/Cargo.toml +++ b/crates/ra_lsp_server/Cargo.toml | |||
@@ -28,6 +28,7 @@ ra_prof = { path = "../ra_prof" } | |||
28 | ra_vfs_glob = { path = "../ra_vfs_glob" } | 28 | ra_vfs_glob = { path = "../ra_vfs_glob" } |
29 | env_logger = { version = "0.7.1", default-features = false, features = ["humantime"] } | 29 | env_logger = { version = "0.7.1", default-features = false, features = ["humantime"] } |
30 | ra_cargo_watch = { path = "../ra_cargo_watch" } | 30 | ra_cargo_watch = { path = "../ra_cargo_watch" } |
31 | itertools = "0.8" | ||
31 | 32 | ||
32 | [dev-dependencies] | 33 | [dev-dependencies] |
33 | tempfile = "3" | 34 | tempfile = "3" |
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index ec3c0a557..d76639474 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs | |||
@@ -3,6 +3,7 @@ | |||
3 | 3 | ||
4 | use std::{fmt::Write as _, io::Write as _}; | 4 | use std::{fmt::Write as _, io::Write as _}; |
5 | 5 | ||
6 | use itertools::Either; | ||
6 | use lsp_server::ErrorCode; | 7 | use lsp_server::ErrorCode; |
7 | use lsp_types::{ | 8 | use lsp_types::{ |
8 | CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem, | 9 | CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem, |
@@ -698,18 +699,25 @@ pub fn handle_code_action( | |||
698 | 699 | ||
699 | for assist in world.analysis().assists(FileRange { file_id, range })?.into_iter() { | 700 | for assist in world.analysis().assists(FileRange { file_id, range })?.into_iter() { |
700 | let title = assist.label.clone(); | 701 | let title = assist.label.clone(); |
701 | let edit = assist.change.try_conv_with(&world)?; | ||
702 | let alternative_edits = assist | ||
703 | .alternative_changes | ||
704 | .into_iter() | ||
705 | .map(|change| change.try_conv_with(&world)) | ||
706 | .collect::<Result<Vec<_>>>()?; | ||
707 | 702 | ||
708 | let command = Command { | 703 | let command = match assist.change_data { |
709 | title, | 704 | Either::Left(change) => Command { |
710 | command: "rust-analyzer.applySourceChange".to_string(), | 705 | title, |
711 | arguments: Some(vec![to_value(edit).unwrap(), to_value(alternative_edits).unwrap()]), | 706 | command: "rust-analyzer.applySourceChange".to_string(), |
707 | arguments: Some(vec![to_value(change.try_conv_with(&world)?)?]), | ||
708 | }, | ||
709 | Either::Right(changes) => Command { | ||
710 | title, | ||
711 | command: "rust-analyzer.selectAndApplySourceChange".to_string(), | ||
712 | arguments: Some(vec![to_value( | ||
713 | changes | ||
714 | .into_iter() | ||
715 | .map(|change| change.try_conv_with(&world)) | ||
716 | .collect::<Result<Vec<_>>>()?, | ||
717 | )?]), | ||
718 | }, | ||
712 | }; | 719 | }; |
720 | |||
713 | let action = CodeAction { | 721 | let action = CodeAction { |
714 | title: command.title.clone(), | 722 | title: command.title.clone(), |
715 | kind: match assist.id { | 723 | kind: match assist.id { |