diff options
-rw-r--r-- | Cargo.lock | 1 | ||||
-rw-r--r-- | crates/ide_assists/src/lib.rs | 131 | ||||
-rw-r--r-- | crates/ide_db/src/assists.rs | 136 | ||||
-rw-r--r-- | crates/ide_db/src/lib.rs | 1 | ||||
-rw-r--r-- | crates/ide_diagnostics/Cargo.toml | 1 | ||||
-rw-r--r-- | crates/ide_diagnostics/src/incorrect_case.rs | 3 | ||||
-rw-r--r-- | crates/ide_diagnostics/src/lib.rs | 5 | ||||
-rw-r--r-- | crates/ide_diagnostics/src/missing_fields.rs | 3 | ||||
-rw-r--r-- | crates/ide_diagnostics/src/missing_ok_or_some_in_tail_expr.rs | 3 | ||||
-rw-r--r-- | crates/ide_diagnostics/src/unresolved_module.rs | 3 |
10 files changed, 147 insertions, 140 deletions
diff --git a/Cargo.lock b/Cargo.lock index 55016ccf7..847277118 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -678,7 +678,6 @@ dependencies = [ | |||
678 | "either", | 678 | "either", |
679 | "expect-test", | 679 | "expect-test", |
680 | "hir", | 680 | "hir", |
681 | "ide_assists", | ||
682 | "ide_db", | 681 | "ide_db", |
683 | "itertools", | 682 | "itertools", |
684 | "profile", | 683 | "profile", |
diff --git a/crates/ide_assists/src/lib.rs b/crates/ide_assists/src/lib.rs index 804918284..fa378a622 100644 --- a/crates/ide_assists/src/lib.rs +++ b/crates/ide_assists/src/lib.rs | |||
@@ -17,139 +17,16 @@ mod tests; | |||
17 | pub mod utils; | 17 | pub mod utils; |
18 | pub mod path_transform; | 18 | pub mod path_transform; |
19 | 19 | ||
20 | use std::str::FromStr; | ||
21 | |||
22 | use hir::Semantics; | 20 | use hir::Semantics; |
23 | use ide_db::{base_db::FileRange, label::Label, source_change::SourceChange, RootDatabase}; | 21 | use ide_db::{base_db::FileRange, RootDatabase}; |
24 | use syntax::TextRange; | 22 | use syntax::TextRange; |
25 | 23 | ||
26 | pub(crate) use crate::assist_context::{AssistContext, Assists}; | 24 | pub(crate) use crate::assist_context::{AssistContext, Assists}; |
27 | 25 | ||
28 | pub use assist_config::AssistConfig; | 26 | pub use assist_config::AssistConfig; |
29 | 27 | pub use ide_db::assists::{ | |
30 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 28 | Assist, AssistId, AssistKind, AssistResolveStrategy, GroupLabel, SingleResolve, |
31 | pub enum AssistKind { | 29 | }; |
32 | // FIXME: does the None variant make sense? Probably not. | ||
33 | None, | ||
34 | |||
35 | QuickFix, | ||
36 | Generate, | ||
37 | Refactor, | ||
38 | RefactorExtract, | ||
39 | RefactorInline, | ||
40 | RefactorRewrite, | ||
41 | } | ||
42 | |||
43 | impl AssistKind { | ||
44 | pub fn contains(self, other: AssistKind) -> bool { | ||
45 | if self == other { | ||
46 | return true; | ||
47 | } | ||
48 | |||
49 | match self { | ||
50 | AssistKind::None | AssistKind::Generate => true, | ||
51 | AssistKind::Refactor => match other { | ||
52 | AssistKind::RefactorExtract | ||
53 | | AssistKind::RefactorInline | ||
54 | | AssistKind::RefactorRewrite => true, | ||
55 | _ => false, | ||
56 | }, | ||
57 | _ => false, | ||
58 | } | ||
59 | } | ||
60 | |||
61 | pub fn name(&self) -> &str { | ||
62 | match self { | ||
63 | AssistKind::None => "None", | ||
64 | AssistKind::QuickFix => "QuickFix", | ||
65 | AssistKind::Generate => "Generate", | ||
66 | AssistKind::Refactor => "Refactor", | ||
67 | AssistKind::RefactorExtract => "RefactorExtract", | ||
68 | AssistKind::RefactorInline => "RefactorInline", | ||
69 | AssistKind::RefactorRewrite => "RefactorRewrite", | ||
70 | } | ||
71 | } | ||
72 | } | ||
73 | |||
74 | impl FromStr for AssistKind { | ||
75 | type Err = String; | ||
76 | |||
77 | fn from_str(s: &str) -> Result<Self, Self::Err> { | ||
78 | match s { | ||
79 | "None" => Ok(AssistKind::None), | ||
80 | "QuickFix" => Ok(AssistKind::QuickFix), | ||
81 | "Generate" => Ok(AssistKind::Generate), | ||
82 | "Refactor" => Ok(AssistKind::Refactor), | ||
83 | "RefactorExtract" => Ok(AssistKind::RefactorExtract), | ||
84 | "RefactorInline" => Ok(AssistKind::RefactorInline), | ||
85 | "RefactorRewrite" => Ok(AssistKind::RefactorRewrite), | ||
86 | unknown => Err(format!("Unknown AssistKind: '{}'", unknown)), | ||
87 | } | ||
88 | } | ||
89 | } | ||
90 | |||
91 | /// Unique identifier of the assist, should not be shown to the user | ||
92 | /// directly. | ||
93 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
94 | pub struct AssistId(pub &'static str, pub AssistKind); | ||
95 | |||
96 | /// A way to control how many asssist to resolve during the assist resolution. | ||
97 | /// When an assist is resolved, its edits are calculated that might be costly to always do by default. | ||
98 | #[derive(Debug)] | ||
99 | pub enum AssistResolveStrategy { | ||
100 | /// No assists should be resolved. | ||
101 | None, | ||
102 | /// All assists should be resolved. | ||
103 | All, | ||
104 | /// Only a certain assist should be resolved. | ||
105 | Single(SingleResolve), | ||
106 | } | ||
107 | |||
108 | /// Hold the [`AssistId`] data of a certain assist to resolve. | ||
109 | /// The original id object cannot be used due to a `'static` lifetime | ||
110 | /// and the requirement to construct this struct dynamically during the resolve handling. | ||
111 | #[derive(Debug)] | ||
112 | pub struct SingleResolve { | ||
113 | /// The id of the assist. | ||
114 | pub assist_id: String, | ||
115 | // The kind of the assist. | ||
116 | pub assist_kind: AssistKind, | ||
117 | } | ||
118 | |||
119 | impl AssistResolveStrategy { | ||
120 | pub fn should_resolve(&self, id: &AssistId) -> bool { | ||
121 | match self { | ||
122 | AssistResolveStrategy::None => false, | ||
123 | AssistResolveStrategy::All => true, | ||
124 | AssistResolveStrategy::Single(single_resolve) => { | ||
125 | single_resolve.assist_id == id.0 && single_resolve.assist_kind == id.1 | ||
126 | } | ||
127 | } | ||
128 | } | ||
129 | } | ||
130 | |||
131 | #[derive(Clone, Debug)] | ||
132 | pub struct GroupLabel(pub String); | ||
133 | |||
134 | #[derive(Debug, Clone)] | ||
135 | pub struct Assist { | ||
136 | pub id: AssistId, | ||
137 | /// Short description of the assist, as shown in the UI. | ||
138 | pub label: Label, | ||
139 | pub group: Option<GroupLabel>, | ||
140 | /// Target ranges are used to sort assists: the smaller the target range, | ||
141 | /// the more specific assist is, and so it should be sorted first. | ||
142 | pub target: TextRange, | ||
143 | /// Computing source change sometimes is much more costly then computing the | ||
144 | /// other fields. Additionally, the actual change is not required to show | ||
145 | /// the lightbulb UI, it only is needed when the user tries to apply an | ||
146 | /// assist. So, we compute it lazily: the API allow requesting assists with | ||
147 | /// or without source change. We could (and in fact, used to) distinguish | ||
148 | /// between resolved and unresolved assists at the type level, but this is | ||
149 | /// cumbersome, especially if you want to embed an assist into another data | ||
150 | /// structure, such as a diagnostic. | ||
151 | pub source_change: Option<SourceChange>, | ||
152 | } | ||
153 | 30 | ||
154 | /// Return all the assists applicable at the given position. | 31 | /// Return all the assists applicable at the given position. |
155 | pub fn assists( | 32 | pub fn assists( |
diff --git a/crates/ide_db/src/assists.rs b/crates/ide_db/src/assists.rs new file mode 100644 index 000000000..7881d8369 --- /dev/null +++ b/crates/ide_db/src/assists.rs | |||
@@ -0,0 +1,136 @@ | |||
1 | //! This module defines the `Assist` data structure. The actual assist live in | ||
2 | //! the `ide_assists` downstream crate. We want to define the data structures in | ||
3 | //! this low-level crate though, because `ide_diagnostics` also need them | ||
4 | //! (fixits for diagnostics and assists are the same thing under the hood). We | ||
5 | //! want to compile `ide_assists` and `ide_diagnostics` in parallel though, so | ||
6 | //! we pull the common definitions upstream, to this crate. | ||
7 | |||
8 | use std::str::FromStr; | ||
9 | |||
10 | use syntax::TextRange; | ||
11 | |||
12 | use crate::{label::Label, source_change::SourceChange}; | ||
13 | |||
14 | #[derive(Debug, Clone)] | ||
15 | pub struct Assist { | ||
16 | pub id: AssistId, | ||
17 | /// Short description of the assist, as shown in the UI. | ||
18 | pub label: Label, | ||
19 | pub group: Option<GroupLabel>, | ||
20 | /// Target ranges are used to sort assists: the smaller the target range, | ||
21 | /// the more specific assist is, and so it should be sorted first. | ||
22 | pub target: TextRange, | ||
23 | /// Computing source change sometimes is much more costly then computing the | ||
24 | /// other fields. Additionally, the actual change is not required to show | ||
25 | /// the lightbulb UI, it only is needed when the user tries to apply an | ||
26 | /// assist. So, we compute it lazily: the API allow requesting assists with | ||
27 | /// or without source change. We could (and in fact, used to) distinguish | ||
28 | /// between resolved and unresolved assists at the type level, but this is | ||
29 | /// cumbersome, especially if you want to embed an assist into another data | ||
30 | /// structure, such as a diagnostic. | ||
31 | pub source_change: Option<SourceChange>, | ||
32 | } | ||
33 | |||
34 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
35 | pub enum AssistKind { | ||
36 | // FIXME: does the None variant make sense? Probably not. | ||
37 | None, | ||
38 | |||
39 | QuickFix, | ||
40 | Generate, | ||
41 | Refactor, | ||
42 | RefactorExtract, | ||
43 | RefactorInline, | ||
44 | RefactorRewrite, | ||
45 | } | ||
46 | |||
47 | impl AssistKind { | ||
48 | pub fn contains(self, other: AssistKind) -> bool { | ||
49 | if self == other { | ||
50 | return true; | ||
51 | } | ||
52 | |||
53 | match self { | ||
54 | AssistKind::None | AssistKind::Generate => true, | ||
55 | AssistKind::Refactor => match other { | ||
56 | AssistKind::RefactorExtract | ||
57 | | AssistKind::RefactorInline | ||
58 | | AssistKind::RefactorRewrite => true, | ||
59 | _ => false, | ||
60 | }, | ||
61 | _ => false, | ||
62 | } | ||
63 | } | ||
64 | |||
65 | pub fn name(&self) -> &str { | ||
66 | match self { | ||
67 | AssistKind::None => "None", | ||
68 | AssistKind::QuickFix => "QuickFix", | ||
69 | AssistKind::Generate => "Generate", | ||
70 | AssistKind::Refactor => "Refactor", | ||
71 | AssistKind::RefactorExtract => "RefactorExtract", | ||
72 | AssistKind::RefactorInline => "RefactorInline", | ||
73 | AssistKind::RefactorRewrite => "RefactorRewrite", | ||
74 | } | ||
75 | } | ||
76 | } | ||
77 | |||
78 | impl FromStr for AssistKind { | ||
79 | type Err = String; | ||
80 | |||
81 | fn from_str(s: &str) -> Result<Self, Self::Err> { | ||
82 | match s { | ||
83 | "None" => Ok(AssistKind::None), | ||
84 | "QuickFix" => Ok(AssistKind::QuickFix), | ||
85 | "Generate" => Ok(AssistKind::Generate), | ||
86 | "Refactor" => Ok(AssistKind::Refactor), | ||
87 | "RefactorExtract" => Ok(AssistKind::RefactorExtract), | ||
88 | "RefactorInline" => Ok(AssistKind::RefactorInline), | ||
89 | "RefactorRewrite" => Ok(AssistKind::RefactorRewrite), | ||
90 | unknown => Err(format!("Unknown AssistKind: '{}'", unknown)), | ||
91 | } | ||
92 | } | ||
93 | } | ||
94 | |||
95 | /// Unique identifier of the assist, should not be shown to the user | ||
96 | /// directly. | ||
97 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
98 | pub struct AssistId(pub &'static str, pub AssistKind); | ||
99 | |||
100 | /// A way to control how many asssist to resolve during the assist resolution. | ||
101 | /// When an assist is resolved, its edits are calculated that might be costly to always do by default. | ||
102 | #[derive(Debug)] | ||
103 | pub enum AssistResolveStrategy { | ||
104 | /// No assists should be resolved. | ||
105 | None, | ||
106 | /// All assists should be resolved. | ||
107 | All, | ||
108 | /// Only a certain assist should be resolved. | ||
109 | Single(SingleResolve), | ||
110 | } | ||
111 | |||
112 | /// Hold the [`AssistId`] data of a certain assist to resolve. | ||
113 | /// The original id object cannot be used due to a `'static` lifetime | ||
114 | /// and the requirement to construct this struct dynamically during the resolve handling. | ||
115 | #[derive(Debug)] | ||
116 | pub struct SingleResolve { | ||
117 | /// The id of the assist. | ||
118 | pub assist_id: String, | ||
119 | // The kind of the assist. | ||
120 | pub assist_kind: AssistKind, | ||
121 | } | ||
122 | |||
123 | impl AssistResolveStrategy { | ||
124 | pub fn should_resolve(&self, id: &AssistId) -> bool { | ||
125 | match self { | ||
126 | AssistResolveStrategy::None => false, | ||
127 | AssistResolveStrategy::All => true, | ||
128 | AssistResolveStrategy::Single(single_resolve) => { | ||
129 | single_resolve.assist_id == id.0 && single_resolve.assist_kind == id.1 | ||
130 | } | ||
131 | } | ||
132 | } | ||
133 | } | ||
134 | |||
135 | #[derive(Clone, Debug)] | ||
136 | pub struct GroupLabel(pub String); | ||
diff --git a/crates/ide_db/src/lib.rs b/crates/ide_db/src/lib.rs index 105607dca..2ac215c06 100644 --- a/crates/ide_db/src/lib.rs +++ b/crates/ide_db/src/lib.rs | |||
@@ -3,6 +3,7 @@ | |||
3 | //! It is mainly a `HirDatabase` for semantic analysis, plus a `SymbolsDatabase`, for fuzzy search. | 3 | //! It is mainly a `HirDatabase` for semantic analysis, plus a `SymbolsDatabase`, for fuzzy search. |
4 | 4 | ||
5 | mod apply_change; | 5 | mod apply_change; |
6 | pub mod assists; | ||
6 | pub mod label; | 7 | pub mod label; |
7 | pub mod line_index; | 8 | pub mod line_index; |
8 | pub mod symbol_index; | 9 | pub mod symbol_index; |
diff --git a/crates/ide_diagnostics/Cargo.toml b/crates/ide_diagnostics/Cargo.toml index 738fca14e..fa2adf212 100644 --- a/crates/ide_diagnostics/Cargo.toml +++ b/crates/ide_diagnostics/Cargo.toml | |||
@@ -22,7 +22,6 @@ text_edit = { path = "../text_edit", version = "0.0.0" } | |||
22 | cfg = { path = "../cfg", version = "0.0.0" } | 22 | cfg = { path = "../cfg", version = "0.0.0" } |
23 | hir = { path = "../hir", version = "0.0.0" } | 23 | hir = { path = "../hir", version = "0.0.0" } |
24 | ide_db = { path = "../ide_db", version = "0.0.0" } | 24 | ide_db = { path = "../ide_db", version = "0.0.0" } |
25 | ide_assists = { path = "../ide_assists", version = "0.0.0" } | ||
26 | 25 | ||
27 | [dev-dependencies] | 26 | [dev-dependencies] |
28 | expect-test = "1.1" | 27 | expect-test = "1.1" |
diff --git a/crates/ide_diagnostics/src/incorrect_case.rs b/crates/ide_diagnostics/src/incorrect_case.rs index 04fc779ce..8e1a93aa7 100644 --- a/crates/ide_diagnostics/src/incorrect_case.rs +++ b/crates/ide_diagnostics/src/incorrect_case.rs | |||
@@ -1,6 +1,5 @@ | |||
1 | use hir::{db::AstDatabase, InFile}; | 1 | use hir::{db::AstDatabase, InFile}; |
2 | use ide_assists::Assist; | 2 | use ide_db::{assists::Assist, base_db::FilePosition}; |
3 | use ide_db::base_db::FilePosition; | ||
4 | use syntax::AstNode; | 3 | use syntax::AstNode; |
5 | 4 | ||
6 | use crate::{ | 5 | use crate::{ |
diff --git a/crates/ide_diagnostics/src/lib.rs b/crates/ide_diagnostics/src/lib.rs index 0d98307a2..2a16c73a8 100644 --- a/crates/ide_diagnostics/src/lib.rs +++ b/crates/ide_diagnostics/src/lib.rs | |||
@@ -28,6 +28,7 @@ mod field_shorthand; | |||
28 | 28 | ||
29 | use hir::{diagnostics::AnyDiagnostic, Semantics}; | 29 | use hir::{diagnostics::AnyDiagnostic, Semantics}; |
30 | use ide_db::{ | 30 | use ide_db::{ |
31 | assists::{Assist, AssistId, AssistKind, AssistResolveStrategy}, | ||
31 | base_db::{FileId, SourceDatabase}, | 32 | base_db::{FileId, SourceDatabase}, |
32 | label::Label, | 33 | label::Label, |
33 | source_change::SourceChange, | 34 | source_change::SourceChange, |
@@ -42,8 +43,6 @@ use syntax::{ | |||
42 | use text_edit::TextEdit; | 43 | use text_edit::TextEdit; |
43 | use unlinked_file::UnlinkedFile; | 44 | use unlinked_file::UnlinkedFile; |
44 | 45 | ||
45 | use ide_assists::{Assist, AssistId, AssistKind, AssistResolveStrategy}; | ||
46 | |||
47 | #[derive(Copy, Clone, Debug, PartialEq)] | 46 | #[derive(Copy, Clone, Debug, PartialEq)] |
48 | pub struct DiagnosticCode(pub &'static str); | 47 | pub struct DiagnosticCode(pub &'static str); |
49 | 48 | ||
@@ -265,8 +264,8 @@ fn unresolved_fix(id: &'static str, label: &str, target: TextRange) -> Assist { | |||
265 | #[cfg(test)] | 264 | #[cfg(test)] |
266 | mod tests { | 265 | mod tests { |
267 | use expect_test::Expect; | 266 | use expect_test::Expect; |
268 | use ide_assists::AssistResolveStrategy; | ||
269 | use ide_db::{ | 267 | use ide_db::{ |
268 | assists::AssistResolveStrategy, | ||
270 | base_db::{fixture::WithFixture, SourceDatabaseExt}, | 269 | base_db::{fixture::WithFixture, SourceDatabaseExt}, |
271 | RootDatabase, | 270 | RootDatabase, |
272 | }; | 271 | }; |
diff --git a/crates/ide_diagnostics/src/missing_fields.rs b/crates/ide_diagnostics/src/missing_fields.rs index f242ee481..5af67f461 100644 --- a/crates/ide_diagnostics/src/missing_fields.rs +++ b/crates/ide_diagnostics/src/missing_fields.rs | |||
@@ -1,7 +1,6 @@ | |||
1 | use either::Either; | 1 | use either::Either; |
2 | use hir::{db::AstDatabase, InFile}; | 2 | use hir::{db::AstDatabase, InFile}; |
3 | use ide_assists::Assist; | 3 | use ide_db::{assists::Assist, source_change::SourceChange}; |
4 | use ide_db::source_change::SourceChange; | ||
5 | use stdx::format_to; | 4 | use stdx::format_to; |
6 | use syntax::{algo, ast::make, AstNode, SyntaxNodePtr}; | 5 | use syntax::{algo, ast::make, AstNode, SyntaxNodePtr}; |
7 | use text_edit::TextEdit; | 6 | use text_edit::TextEdit; |
diff --git a/crates/ide_diagnostics/src/missing_ok_or_some_in_tail_expr.rs b/crates/ide_diagnostics/src/missing_ok_or_some_in_tail_expr.rs index 9e36ca296..01c79b6f5 100644 --- a/crates/ide_diagnostics/src/missing_ok_or_some_in_tail_expr.rs +++ b/crates/ide_diagnostics/src/missing_ok_or_some_in_tail_expr.rs | |||
@@ -1,6 +1,5 @@ | |||
1 | use hir::db::AstDatabase; | 1 | use hir::db::AstDatabase; |
2 | use ide_assists::Assist; | 2 | use ide_db::{assists::Assist, source_change::SourceChange}; |
3 | use ide_db::source_change::SourceChange; | ||
4 | use syntax::AstNode; | 3 | use syntax::AstNode; |
5 | use text_edit::TextEdit; | 4 | use text_edit::TextEdit; |
6 | 5 | ||
diff --git a/crates/ide_diagnostics/src/unresolved_module.rs b/crates/ide_diagnostics/src/unresolved_module.rs index b11e71b3e..5aa9dae17 100644 --- a/crates/ide_diagnostics/src/unresolved_module.rs +++ b/crates/ide_diagnostics/src/unresolved_module.rs | |||
@@ -1,6 +1,5 @@ | |||
1 | use hir::db::AstDatabase; | 1 | use hir::db::AstDatabase; |
2 | use ide_assists::Assist; | 2 | use ide_db::{assists::Assist, base_db::AnchoredPathBuf, source_change::FileSystemEdit}; |
3 | use ide_db::{base_db::AnchoredPathBuf, source_change::FileSystemEdit}; | ||
4 | use syntax::AstNode; | 3 | use syntax::AstNode; |
5 | 4 | ||
6 | use crate::{fix, Diagnostic, DiagnosticsContext}; | 5 | use crate::{fix, Diagnostic, DiagnosticsContext}; |