diff options
Diffstat (limited to 'crates/ra_assists')
-rw-r--r-- | crates/ra_assists/src/assist_config.rs | 5 | ||||
-rw-r--r-- | crates/ra_assists/src/assist_context.rs | 34 | ||||
-rw-r--r-- | crates/ra_assists/src/lib.rs | 19 | ||||
-rw-r--r-- | crates/ra_assists/src/tests.rs | 45 |
4 files changed, 98 insertions, 5 deletions
diff --git a/crates/ra_assists/src/assist_config.rs b/crates/ra_assists/src/assist_config.rs index c0a0226fb..cda2abfb9 100644 --- a/crates/ra_assists/src/assist_config.rs +++ b/crates/ra_assists/src/assist_config.rs | |||
@@ -4,9 +4,12 @@ | |||
4 | //! module, and we use to statically check that we only produce snippet | 4 | //! module, and we use to statically check that we only produce snippet |
5 | //! assists if we are allowed to. | 5 | //! assists if we are allowed to. |
6 | 6 | ||
7 | use crate::AssistKind; | ||
8 | |||
7 | #[derive(Clone, Debug, PartialEq, Eq)] | 9 | #[derive(Clone, Debug, PartialEq, Eq)] |
8 | pub struct AssistConfig { | 10 | pub struct AssistConfig { |
9 | pub snippet_cap: Option<SnippetCap>, | 11 | pub snippet_cap: Option<SnippetCap>, |
12 | pub allowed: Option<Vec<AssistKind>>, | ||
10 | } | 13 | } |
11 | 14 | ||
12 | impl AssistConfig { | 15 | impl AssistConfig { |
@@ -22,6 +25,6 @@ pub struct SnippetCap { | |||
22 | 25 | ||
23 | impl Default for AssistConfig { | 26 | impl Default for AssistConfig { |
24 | fn default() -> Self { | 27 | fn default() -> Self { |
25 | AssistConfig { snippet_cap: Some(SnippetCap { _private: () }) } | 28 | AssistConfig { snippet_cap: Some(SnippetCap { _private: () }), allowed: None } |
26 | } | 29 | } |
27 | } | 30 | } |
diff --git a/crates/ra_assists/src/assist_context.rs b/crates/ra_assists/src/assist_context.rs index c33525363..3407df856 100644 --- a/crates/ra_assists/src/assist_context.rs +++ b/crates/ra_assists/src/assist_context.rs | |||
@@ -19,7 +19,7 @@ use ra_text_edit::TextEditBuilder; | |||
19 | 19 | ||
20 | use crate::{ | 20 | use crate::{ |
21 | assist_config::{AssistConfig, SnippetCap}, | 21 | assist_config::{AssistConfig, SnippetCap}, |
22 | Assist, AssistId, GroupLabel, ResolvedAssist, | 22 | Assist, AssistId, AssistKind, GroupLabel, ResolvedAssist, |
23 | }; | 23 | }; |
24 | 24 | ||
25 | /// `AssistContext` allows to apply an assist or check if it could be applied. | 25 | /// `AssistContext` allows to apply an assist or check if it could be applied. |
@@ -103,14 +103,26 @@ pub(crate) struct Assists { | |||
103 | resolve: bool, | 103 | resolve: bool, |
104 | file: FileId, | 104 | file: FileId, |
105 | buf: Vec<(Assist, Option<SourceChange>)>, | 105 | buf: Vec<(Assist, Option<SourceChange>)>, |
106 | allowed: Option<Vec<AssistKind>>, | ||
106 | } | 107 | } |
107 | 108 | ||
108 | impl Assists { | 109 | impl Assists { |
109 | pub(crate) fn new_resolved(ctx: &AssistContext) -> Assists { | 110 | pub(crate) fn new_resolved(ctx: &AssistContext) -> Assists { |
110 | Assists { resolve: true, file: ctx.frange.file_id, buf: Vec::new() } | 111 | Assists { |
112 | resolve: true, | ||
113 | file: ctx.frange.file_id, | ||
114 | buf: Vec::new(), | ||
115 | allowed: ctx.config.allowed.clone(), | ||
116 | } | ||
111 | } | 117 | } |
118 | |||
112 | pub(crate) fn new_unresolved(ctx: &AssistContext) -> Assists { | 119 | pub(crate) fn new_unresolved(ctx: &AssistContext) -> Assists { |
113 | Assists { resolve: false, file: ctx.frange.file_id, buf: Vec::new() } | 120 | Assists { |
121 | resolve: false, | ||
122 | file: ctx.frange.file_id, | ||
123 | buf: Vec::new(), | ||
124 | allowed: ctx.config.allowed.clone(), | ||
125 | } | ||
114 | } | 126 | } |
115 | 127 | ||
116 | pub(crate) fn finish_unresolved(self) -> Vec<Assist> { | 128 | pub(crate) fn finish_unresolved(self) -> Vec<Assist> { |
@@ -139,9 +151,13 @@ impl Assists { | |||
139 | target: TextRange, | 151 | target: TextRange, |
140 | f: impl FnOnce(&mut AssistBuilder), | 152 | f: impl FnOnce(&mut AssistBuilder), |
141 | ) -> Option<()> { | 153 | ) -> Option<()> { |
154 | if !self.is_allowed(&id) { | ||
155 | return None; | ||
156 | } | ||
142 | let label = Assist::new(id, label.into(), None, target); | 157 | let label = Assist::new(id, label.into(), None, target); |
143 | self.add_impl(label, f) | 158 | self.add_impl(label, f) |
144 | } | 159 | } |
160 | |||
145 | pub(crate) fn add_group( | 161 | pub(crate) fn add_group( |
146 | &mut self, | 162 | &mut self, |
147 | group: &GroupLabel, | 163 | group: &GroupLabel, |
@@ -150,9 +166,14 @@ impl Assists { | |||
150 | target: TextRange, | 166 | target: TextRange, |
151 | f: impl FnOnce(&mut AssistBuilder), | 167 | f: impl FnOnce(&mut AssistBuilder), |
152 | ) -> Option<()> { | 168 | ) -> Option<()> { |
169 | if !self.is_allowed(&id) { | ||
170 | return None; | ||
171 | } | ||
172 | |||
153 | let label = Assist::new(id, label.into(), Some(group.clone()), target); | 173 | let label = Assist::new(id, label.into(), Some(group.clone()), target); |
154 | self.add_impl(label, f) | 174 | self.add_impl(label, f) |
155 | } | 175 | } |
176 | |||
156 | fn add_impl(&mut self, label: Assist, f: impl FnOnce(&mut AssistBuilder)) -> Option<()> { | 177 | fn add_impl(&mut self, label: Assist, f: impl FnOnce(&mut AssistBuilder)) -> Option<()> { |
157 | let source_change = if self.resolve { | 178 | let source_change = if self.resolve { |
158 | let mut builder = AssistBuilder::new(self.file); | 179 | let mut builder = AssistBuilder::new(self.file); |
@@ -170,6 +191,13 @@ impl Assists { | |||
170 | self.buf.sort_by_key(|(label, _edit)| label.target.len()); | 191 | self.buf.sort_by_key(|(label, _edit)| label.target.len()); |
171 | self.buf | 192 | self.buf |
172 | } | 193 | } |
194 | |||
195 | fn is_allowed(&self, id: &AssistId) -> bool { | ||
196 | match &self.allowed { | ||
197 | Some(allowed) => allowed.iter().any(|kind| kind.contains(id.1)), | ||
198 | None => true, | ||
199 | } | ||
200 | } | ||
173 | } | 201 | } |
174 | 202 | ||
175 | pub(crate) struct AssistBuilder { | 203 | pub(crate) struct AssistBuilder { |
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index 3d61fbded..465b90415 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs | |||
@@ -37,6 +37,25 @@ pub enum AssistKind { | |||
37 | RefactorRewrite, | 37 | RefactorRewrite, |
38 | } | 38 | } |
39 | 39 | ||
40 | impl AssistKind { | ||
41 | pub fn contains(self, other: AssistKind) -> bool { | ||
42 | if self == other { | ||
43 | return true; | ||
44 | } | ||
45 | |||
46 | match self { | ||
47 | AssistKind::None | AssistKind::Generate => return true, | ||
48 | AssistKind::Refactor => match other { | ||
49 | AssistKind::RefactorExtract | ||
50 | | AssistKind::RefactorInline | ||
51 | | AssistKind::RefactorRewrite => return true, | ||
52 | _ => return false, | ||
53 | }, | ||
54 | _ => return false, | ||
55 | } | ||
56 | } | ||
57 | } | ||
58 | |||
40 | /// Unique identifier of the assist, should not be shown to the user | 59 | /// Unique identifier of the assist, should not be shown to the user |
41 | /// directly. | 60 | /// directly. |
42 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 61 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
diff --git a/crates/ra_assists/src/tests.rs b/crates/ra_assists/src/tests.rs index 858f5ca80..18fcb9049 100644 --- a/crates/ra_assists/src/tests.rs +++ b/crates/ra_assists/src/tests.rs | |||
@@ -6,7 +6,7 @@ use ra_ide_db::RootDatabase; | |||
6 | use ra_syntax::TextRange; | 6 | use ra_syntax::TextRange; |
7 | use test_utils::{assert_eq_text, extract_offset, extract_range}; | 7 | use test_utils::{assert_eq_text, extract_offset, extract_range}; |
8 | 8 | ||
9 | use crate::{handlers::Handler, Assist, AssistConfig, AssistContext, Assists}; | 9 | use crate::{handlers::Handler, Assist, AssistConfig, AssistContext, AssistKind, Assists}; |
10 | use stdx::trim_indent; | 10 | use stdx::trim_indent; |
11 | 11 | ||
12 | pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) { | 12 | pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) { |
@@ -134,3 +134,46 @@ fn assist_order_if_expr() { | |||
134 | assert_eq!(assists.next().expect("expected assist").assist.label, "Extract into variable"); | 134 | assert_eq!(assists.next().expect("expected assist").assist.label, "Extract into variable"); |
135 | assert_eq!(assists.next().expect("expected assist").assist.label, "Replace with match"); | 135 | assert_eq!(assists.next().expect("expected assist").assist.label, "Replace with match"); |
136 | } | 136 | } |
137 | |||
138 | #[test] | ||
139 | fn assist_filter_works() { | ||
140 | let before = " | ||
141 | pub fn test_some_range(a: int) -> bool { | ||
142 | if let 2..6 = <|>5<|> { | ||
143 | true | ||
144 | } else { | ||
145 | false | ||
146 | } | ||
147 | }"; | ||
148 | let (range, before) = extract_range(before); | ||
149 | let (db, file_id) = with_single_file(&before); | ||
150 | let frange = FileRange { file_id, range }; | ||
151 | |||
152 | { | ||
153 | let mut cfg = AssistConfig::default(); | ||
154 | cfg.allowed = Some(vec![AssistKind::Refactor]); | ||
155 | |||
156 | let assists = Assist::resolved(&db, &cfg, frange); | ||
157 | let mut assists = assists.iter(); | ||
158 | |||
159 | assert_eq!(assists.next().expect("expected assist").assist.label, "Extract into variable"); | ||
160 | assert_eq!(assists.next().expect("expected assist").assist.label, "Replace with match"); | ||
161 | } | ||
162 | |||
163 | { | ||
164 | let mut cfg = AssistConfig::default(); | ||
165 | cfg.allowed = Some(vec![AssistKind::RefactorExtract]); | ||
166 | let assists = Assist::resolved(&db, &cfg, frange); | ||
167 | assert_eq!(assists.len(), 1); | ||
168 | |||
169 | let mut assists = assists.iter(); | ||
170 | assert_eq!(assists.next().expect("expected assist").assist.label, "Extract into variable"); | ||
171 | } | ||
172 | |||
173 | { | ||
174 | let mut cfg = AssistConfig::default(); | ||
175 | cfg.allowed = Some(vec![AssistKind::QuickFix]); | ||
176 | let assists = Assist::resolved(&db, &cfg, frange); | ||
177 | assert!(assists.is_empty(), "All asserts but quickfixes should be filtered out"); | ||
178 | } | ||
179 | } | ||