diff options
Diffstat (limited to 'crates/ra_assists/src/assist_ctx.rs')
-rw-r--r-- | crates/ra_assists/src/assist_ctx.rs | 60 |
1 files changed, 51 insertions, 9 deletions
diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs index 28152f724..43f0d664b 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 either::Either; |
3 | use hir::{db::HirDatabase, InFile, SourceAnalyzer, SourceBinder}; | ||
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 }, | 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. |
@@ -81,16 +82,45 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> { | |||
81 | self, | 82 | self, |
82 | id: AssistId, | 83 | id: AssistId, |
83 | label: impl Into<String>, | 84 | label: impl Into<String>, |
84 | f: impl FnOnce(&mut AssistBuilder), | 85 | f: impl FnOnce(&mut ActionBuilder), |
85 | ) -> Option<Assist> { | 86 | ) -> Option<Assist> { |
86 | let label = AssistLabel { label: label.into(), id }; | 87 | let label = AssistLabel { label: label.into(), id }; |
88 | assert!(label.label.chars().nth(0).unwrap().is_uppercase()); | ||
89 | |||
87 | let assist = if self.should_compute_edit { | 90 | let assist = if self.should_compute_edit { |
88 | let action = { | 91 | let action = { |
89 | let mut edit = AssistBuilder::default(); | 92 | let mut edit = ActionBuilder::default(); |
90 | f(&mut edit); | 93 | f(&mut edit); |
91 | edit.build() | 94 | edit.build() |
92 | }; | 95 | }; |
93 | Assist::Resolved { label, action } | 96 | Assist::Resolved { assist: ResolvedAssist { label, action_data: Either::Left(action) } } |
97 | } else { | ||
98 | Assist::Unresolved { label } | ||
99 | }; | ||
100 | |||
101 | Some(assist) | ||
102 | } | ||
103 | |||
104 | #[allow(dead_code)] // will be used for auto import assist with multiple actions | ||
105 | pub(crate) fn add_assist_group( | ||
106 | self, | ||
107 | id: AssistId, | ||
108 | label: impl Into<String>, | ||
109 | f: impl FnOnce() -> Vec<ActionBuilder>, | ||
110 | ) -> Option<Assist> { | ||
111 | let label = AssistLabel { label: label.into(), id }; | ||
112 | let assist = if self.should_compute_edit { | ||
113 | let actions = f(); | ||
114 | assert!(!actions.is_empty(), "Assist cannot have no"); | ||
115 | |||
116 | Assist::Resolved { | ||
117 | assist: ResolvedAssist { | ||
118 | label, | ||
119 | action_data: Either::Right( | ||
120 | actions.into_iter().map(ActionBuilder::build).collect(), | ||
121 | ), | ||
122 | }, | ||
123 | } | ||
94 | } else { | 124 | } else { |
95 | Assist::Unresolved { label } | 125 | Assist::Unresolved { label } |
96 | }; | 126 | }; |
@@ -112,12 +142,16 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> { | |||
112 | pub(crate) fn covering_element(&self) -> SyntaxElement { | 142 | pub(crate) fn covering_element(&self) -> SyntaxElement { |
113 | find_covering_element(self.source_file.syntax(), self.frange.range) | 143 | find_covering_element(self.source_file.syntax(), self.frange.range) |
114 | } | 144 | } |
145 | pub(crate) fn source_binder(&self) -> SourceBinder<'a, DB> { | ||
146 | SourceBinder::new(self.db) | ||
147 | } | ||
115 | pub(crate) fn source_analyzer( | 148 | pub(crate) fn source_analyzer( |
116 | &self, | 149 | &self, |
117 | node: &SyntaxNode, | 150 | node: &SyntaxNode, |
118 | offset: Option<TextUnit>, | 151 | offset: Option<TextUnit>, |
119 | ) -> SourceAnalyzer { | 152 | ) -> SourceAnalyzer { |
120 | SourceAnalyzer::new(self.db, InFile::new(self.frange.file_id.into(), node), offset) | 153 | let src = InFile::new(self.frange.file_id.into(), node); |
154 | self.source_binder().analyze(src, offset) | ||
121 | } | 155 | } |
122 | 156 | ||
123 | pub(crate) fn covering_node_for_range(&self, range: TextRange) -> SyntaxElement { | 157 | pub(crate) fn covering_node_for_range(&self, range: TextRange) -> SyntaxElement { |
@@ -126,13 +160,20 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> { | |||
126 | } | 160 | } |
127 | 161 | ||
128 | #[derive(Default)] | 162 | #[derive(Default)] |
129 | pub(crate) struct AssistBuilder { | 163 | pub(crate) struct ActionBuilder { |
130 | edit: TextEditBuilder, | 164 | edit: TextEditBuilder, |
131 | cursor_position: Option<TextUnit>, | 165 | cursor_position: Option<TextUnit>, |
132 | target: Option<TextRange>, | 166 | target: Option<TextRange>, |
167 | label: Option<String>, | ||
133 | } | 168 | } |
134 | 169 | ||
135 | impl AssistBuilder { | 170 | impl ActionBuilder { |
171 | #[allow(dead_code)] | ||
172 | /// Adds a custom label to the action, if it needs to be different from the assist label | ||
173 | pub(crate) fn label(&mut self, label: impl Into<String>) { | ||
174 | self.label = Some(label.into()) | ||
175 | } | ||
176 | |||
136 | /// Replaces specified `range` of text with a given string. | 177 | /// Replaces specified `range` of text with a given string. |
137 | pub(crate) fn replace(&mut self, range: TextRange, replace_with: impl Into<String>) { | 178 | pub(crate) fn replace(&mut self, range: TextRange, replace_with: impl Into<String>) { |
138 | self.edit.replace(range, replace_with.into()) | 179 | self.edit.replace(range, replace_with.into()) |
@@ -191,6 +232,7 @@ impl AssistBuilder { | |||
191 | edit: self.edit.finish(), | 232 | edit: self.edit.finish(), |
192 | cursor_position: self.cursor_position, | 233 | cursor_position: self.cursor_position, |
193 | target: self.target, | 234 | target: self.target, |
235 | label: self.label, | ||
194 | } | 236 | } |
195 | } | 237 | } |
196 | } | 238 | } |