1 use crate::{
2     Command, Diagnostic, PartialResultParams, Range, TextDocumentIdentifier,
3     WorkDoneProgressOptions, WorkDoneProgressParams, WorkspaceEdit,
4 };
5 use serde::{Deserialize, Serialize};
6 
7 use serde_json::Value;
8 
9 use std::borrow::Cow;
10 #[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
11 #[serde(untagged)]
12 pub enum CodeActionProviderCapability {
13     Simple(bool),
14     Options(CodeActionOptions),
15 }
16 
17 impl From<CodeActionOptions> for CodeActionProviderCapability {
from(from: CodeActionOptions) -> Self18     fn from(from: CodeActionOptions) -> Self {
19         Self::Options(from)
20     }
21 }
22 
23 impl From<bool> for CodeActionProviderCapability {
from(from: bool) -> Self24     fn from(from: bool) -> Self {
25         Self::Simple(from)
26     }
27 }
28 
29 #[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
30 #[serde(rename_all = "camelCase")]
31 pub struct CodeActionClientCapabilities {
32     ///
33     /// This capability supports dynamic registration.
34     ///
35     #[serde(skip_serializing_if = "Option::is_none")]
36     pub dynamic_registration: Option<bool>,
37 
38     /// The client support code action literals as a valid
39     /// response of the `textDocument/codeAction` request.
40     #[serde(skip_serializing_if = "Option::is_none")]
41     pub code_action_literal_support: Option<CodeActionLiteralSupport>,
42 
43     /// Whether code action supports the `isPreferred` property.
44     ///
45     /// since 3.15.0
46     #[serde(skip_serializing_if = "Option::is_none")]
47     pub is_preferred_support: Option<bool>,
48 
49     /// Whether code action supports the `disabled` property.
50     ///
51     /// since 3.16.0
52     #[serde(skip_serializing_if = "Option::is_none")]
53     pub disabled_support: Option<bool>,
54 
55     /// Whether code action supports the `data` property which is
56     /// preserved between a `textDocument/codeAction` and a
57     /// `codeAction/resolve` request.
58     ///
59     /// since 3.16.0
60     #[serde(skip_serializing_if = "Option::is_none")]
61     pub data_support: Option<bool>,
62 
63     /// Whether the client supports resolving additional code action
64     /// properties via a separate `codeAction/resolve` request.
65     ///
66     /// since 3.16.0
67     #[serde(skip_serializing_if = "Option::is_none")]
68     pub resolve_support: Option<CodeActionCapabilityResolveSupport>,
69 
70     /// Whether the client honors the change annotations in
71     /// text edits and resource operations returned via the
72     /// `CodeAction#edit` property by for example presenting
73     /// the workspace edit in the user interface and asking
74     /// for confirmation.
75     ///
76     /// @since 3.16.0
77     #[serde(skip_serializing_if = "Option::is_none")]
78     pub honors_change_annotations: Option<bool>,
79 }
80 
81 /// Whether the client supports resolving additional code action
82 ///  properties via a separate `codeAction/resolve` request.
83 ///
84 /// since 3.16.0
85 #[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
86 #[serde(rename_all = "camelCase")]
87 pub struct CodeActionCapabilityResolveSupport {
88     /// The properties that a client can resolve lazily.
89     pub properties: Vec<String>,
90 }
91 
92 #[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
93 #[serde(rename_all = "camelCase")]
94 pub struct CodeActionLiteralSupport {
95     /// The code action kind is support with the following value set.
96     pub code_action_kind: CodeActionKindLiteralSupport,
97 }
98 
99 #[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
100 #[serde(rename_all = "camelCase")]
101 pub struct CodeActionKindLiteralSupport {
102     /// The code action kind values the client supports. When this
103     /// property exists the client also guarantees that it will
104     /// handle values outside its set gracefully and falls back
105     /// to a default value when unknown.
106     pub value_set: Vec<String>,
107 }
108 
109 /// Params for the CodeActionRequest
110 #[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
111 #[serde(rename_all = "camelCase")]
112 pub struct CodeActionParams {
113     /// The document in which the command was invoked.
114     pub text_document: TextDocumentIdentifier,
115 
116     /// The range for which the command was invoked.
117     pub range: Range,
118 
119     /// Context carrying additional information.
120     pub context: CodeActionContext,
121 
122     #[serde(flatten)]
123     pub work_done_progress_params: WorkDoneProgressParams,
124 
125     #[serde(flatten)]
126     pub partial_result_params: PartialResultParams,
127 }
128 
129 /// response for CodeActionRequest
130 pub type CodeActionResponse = Vec<CodeActionOrCommand>;
131 
132 #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
133 #[serde(untagged)]
134 pub enum CodeActionOrCommand {
135     Command(Command),
136     CodeAction(CodeAction),
137 }
138 
139 impl From<Command> for CodeActionOrCommand {
from(comand: Command) -> Self140     fn from(comand: Command) -> Self {
141         CodeActionOrCommand::Command(comand)
142     }
143 }
144 
145 impl From<CodeAction> for CodeActionOrCommand {
from(action: CodeAction) -> Self146     fn from(action: CodeAction) -> Self {
147         CodeActionOrCommand::CodeAction(action)
148     }
149 }
150 
151 #[derive(Debug, Eq, PartialEq, Hash, PartialOrd, Clone, Deserialize, Serialize)]
152 pub struct CodeActionKind(Cow<'static, str>);
153 
154 impl CodeActionKind {
155     /// Empty kind.
156     pub const EMPTY: CodeActionKind = CodeActionKind::new("");
157 
158     /// Base kind for quickfix actions: 'quickfix'
159     pub const QUICKFIX: CodeActionKind = CodeActionKind::new("quickfix");
160 
161     /// Base kind for refactoring actions: 'refactor'
162     pub const REFACTOR: CodeActionKind = CodeActionKind::new("refactor");
163 
164     /// Base kind for refactoring extraction actions: 'refactor.extract'
165     ///
166     /// Example extract actions:
167     ///
168     /// - Extract method
169     /// - Extract function
170     /// - Extract variable
171     /// - Extract interface from class
172     /// - ...
173     pub const REFACTOR_EXTRACT: CodeActionKind = CodeActionKind::new("refactor.extract");
174 
175     /// Base kind for refactoring inline actions: 'refactor.inline'
176     ///
177     /// Example inline actions:
178     ///
179     /// - Inline function
180     /// - Inline variable
181     /// - Inline constant
182     /// - ...
183     pub const REFACTOR_INLINE: CodeActionKind = CodeActionKind::new("refactor.inline");
184 
185     /// Base kind for refactoring rewrite actions: 'refactor.rewrite'
186     ///
187     /// Example rewrite actions:
188     ///
189     /// - Convert JavaScript function to class
190     /// - Add or remove parameter
191     /// - Encapsulate field
192     /// - Make method static
193     /// - Move method to base class
194     /// - ...
195     pub const REFACTOR_REWRITE: CodeActionKind = CodeActionKind::new("refactor.rewrite");
196 
197     /// Base kind for source actions: `source`
198     ///
199     /// Source code actions apply to the entire file.
200     pub const SOURCE: CodeActionKind = CodeActionKind::new("source");
201 
202     /// Base kind for an organize imports source action: `source.organizeImports`
203     pub const SOURCE_ORGANIZE_IMPORTS: CodeActionKind =
204         CodeActionKind::new("source.organizeImports");
205 
new(tag: &'static str) -> Self206     pub const fn new(tag: &'static str) -> Self {
207         CodeActionKind(Cow::Borrowed(tag))
208     }
209 
as_str(&self) -> &str210     pub fn as_str(&self) -> &str {
211         &self.0
212     }
213 }
214 
215 impl From<String> for CodeActionKind {
from(from: String) -> Self216     fn from(from: String) -> Self {
217         CodeActionKind(Cow::from(from))
218     }
219 }
220 
221 impl From<&'static str> for CodeActionKind {
from(from: &'static str) -> Self222     fn from(from: &'static str) -> Self {
223         CodeActionKind::new(from)
224     }
225 }
226 
227 #[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
228 #[serde(rename_all = "camelCase")]
229 pub struct CodeAction {
230     /// A short, human-readable, title for this code action.
231     pub title: String,
232 
233     /// The kind of the code action.
234     /// Used to filter code actions.
235     #[serde(skip_serializing_if = "Option::is_none")]
236     pub kind: Option<CodeActionKind>,
237 
238     /// The diagnostics that this code action resolves.
239     #[serde(skip_serializing_if = "Option::is_none")]
240     pub diagnostics: Option<Vec<Diagnostic>>,
241 
242     /// The workspace edit this code action performs.
243     #[serde(skip_serializing_if = "Option::is_none")]
244     pub edit: Option<WorkspaceEdit>,
245 
246     /// A command this code action executes. If a code action
247     /// provides an edit and a command, first the edit is
248     /// executed and then the command.
249     #[serde(skip_serializing_if = "Option::is_none")]
250     pub command: Option<Command>,
251 
252     /// Marks this as a preferred action. Preferred actions are used by the `auto fix` command and can be targeted
253     /// by keybindings.
254     /// A quick fix should be marked preferred if it properly addresses the underlying error.
255     /// A refactoring should be marked preferred if it is the most reasonable choice of actions to take.
256     ///
257     /// since 3.15.0
258     #[serde(skip_serializing_if = "Option::is_none")]
259     pub is_preferred: Option<bool>,
260 
261     /// Marks that the code action cannot currently be applied.
262     ///
263     /// Clients should follow the following guidelines regarding disabled code actions:
264     ///
265     /// - Disabled code actions are not shown in automatic
266     ///   [lightbulb](https://code.visualstudio.com/docs/editor/editingevolved#_code-action)
267     ///   code action menu.
268     ///
269     /// - Disabled actions are shown as faded out in the code action menu when the user request
270     ///   a more specific type of code action, such as refactorings.
271     ///
272     /// - If the user has a keybinding that auto applies a code action and only a disabled code
273     ///   actions are returned, the client should show the user an error message with `reason`
274     ///   in the editor.
275     ///
276     /// since 3.16.0
277     #[serde(skip_serializing_if = "Option::is_none")]
278     pub disabled: Option<CodeActionDisabled>,
279 
280     /// A data entry field that is preserved on a code action between
281     /// a `textDocument/codeAction` and a `codeAction/resolve` request.
282     ///
283     /// since 3.16.0
284     #[serde(skip_serializing_if = "Option::is_none")]
285     pub data: Option<Value>,
286 }
287 
288 #[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
289 #[serde(rename_all = "camelCase")]
290 pub struct CodeActionDisabled {
291     /// Human readable description of why the code action is currently disabled.
292     ///
293     /// This is displayed in the code actions UI.
294     pub reason: String,
295 }
296 
297 /// Contains additional diagnostic information about the context in which
298 /// a code action is run.
299 #[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
300 pub struct CodeActionContext {
301     /// An array of diagnostics.
302     pub diagnostics: Vec<Diagnostic>,
303 
304     /// Requested kind of actions to return.
305     ///
306     /// Actions not of this kind are filtered out by the client before being shown. So servers
307     /// can omit computing them.
308     #[serde(skip_serializing_if = "Option::is_none")]
309     pub only: Option<Vec<CodeActionKind>>,
310 }
311 
312 #[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
313 #[serde(rename_all = "camelCase")]
314 pub struct CodeActionOptions {
315     /// CodeActionKinds that this server may return.
316     ///
317     /// The list of kinds may be generic, such as `CodeActionKind.Refactor`, or the server
318     /// may list out every specific kind they provide.
319     #[serde(skip_serializing_if = "Option::is_none")]
320     pub code_action_kinds: Option<Vec<CodeActionKind>>,
321 
322     #[serde(flatten)]
323     pub work_done_progress_options: WorkDoneProgressOptions,
324 
325     /// The server provides support to resolve additional
326     /// information for a code action.
327     ///
328     /// since 3.16.0
329     #[serde(skip_serializing_if = "Option::is_none")]
330     pub resolve_provider: Option<bool>,
331 }
332 
333 #[cfg(test)]
334 mod tests {
335     use super::*;
336     use crate::tests::test_serialization;
337 
338     #[test]
test_code_action_response()339     fn test_code_action_response() {
340         test_serialization(
341             &vec![
342                 CodeActionOrCommand::Command(Command {
343                     title: "title".to_string(),
344                     command: "command".to_string(),
345                     arguments: None,
346                 }),
347                 CodeActionOrCommand::CodeAction(CodeAction {
348                     title: "title".to_string(),
349                     kind: Some(CodeActionKind::QUICKFIX),
350                     command: None,
351                     diagnostics: None,
352                     edit: None,
353                     is_preferred: None,
354                     ..CodeAction::default()
355                 }),
356             ],
357             r#"[{"title":"title","command":"command"},{"title":"title","kind":"quickfix"}]"#,
358         )
359     }
360 }
361