ls_types/
code_action.rs

1use crate::{
2    Command, Diagnostic, PartialResultParams, Range, TextDocumentIdentifier,
3    WorkDoneProgressOptions, WorkDoneProgressParams, WorkspaceEdit, macros::lsp_enum,
4};
5use serde::{Deserialize, Serialize};
6
7use serde_json::Value;
8
9use std::borrow::Cow;
10#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
11#[serde(untagged)]
12pub enum CodeActionProviderCapability {
13    Simple(bool),
14    Options(CodeActionOptions),
15}
16
17impl From<CodeActionOptions> for CodeActionProviderCapability {
18    fn from(from: CodeActionOptions) -> Self {
19        Self::Options(from)
20    }
21}
22
23impl From<bool> for CodeActionProviderCapability {
24    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")]
31pub 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")]
87pub 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")]
94pub 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")]
101pub 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")]
112pub 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`
130pub type CodeActionResponse = Vec<CodeActionOrCommand>;
131
132#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
133#[serde(untagged)]
134pub enum CodeActionOrCommand {
135    Command(Command),
136    CodeAction(CodeAction),
137}
138
139impl From<Command> for CodeActionOrCommand {
140    fn from(command: Command) -> Self {
141        Self::Command(command)
142    }
143}
144
145impl From<CodeAction> for CodeActionOrCommand {
146    fn from(action: CodeAction) -> Self {
147        Self::CodeAction(action)
148    }
149}
150
151#[derive(Debug, Eq, PartialEq, Hash, PartialOrd, Clone, Deserialize, Serialize)]
152pub struct CodeActionKind(Cow<'static, str>);
153
154impl CodeActionKind {
155    /// Empty kind.
156    pub const EMPTY: Self = Self::new("");
157
158    /// Base kind for quickfix actions: 'quickfix'
159    pub const QUICKFIX: Self = Self::new("quickfix");
160
161    /// Base kind for refactoring actions: 'refactor'
162    pub const REFACTOR: Self = Self::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: Self = Self::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: Self = Self::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: Self = Self::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: Self = Self::new("source");
201
202    /// Base kind for an organize imports source action: `source.organizeImports`
203    pub const SOURCE_ORGANIZE_IMPORTS: Self = Self::new("source.organizeImports");
204
205    /// Base kind for a 'fix all' source action: `source.fixAll`.
206    ///
207    /// 'Fix all' actions automatically fix errors that have a clear fix that
208    /// do not require user input. They should not suppress errors or perform
209    /// unsafe fixes such as generating new types or classes.
210    ///
211    /// @since 3.17.0
212    pub const SOURCE_FIX_ALL: Self = Self::new("source.fixAll");
213
214    #[must_use]
215    pub const fn new(tag: &'static str) -> Self {
216        Self(Cow::Borrowed(tag))
217    }
218
219    #[must_use]
220    pub fn as_str(&self) -> &str {
221        &self.0
222    }
223}
224
225impl From<String> for CodeActionKind {
226    fn from(from: String) -> Self {
227        Self(Cow::from(from))
228    }
229}
230
231impl From<&'static str> for CodeActionKind {
232    fn from(from: &'static str) -> Self {
233        Self::new(from)
234    }
235}
236
237#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
238#[serde(rename_all = "camelCase")]
239pub struct CodeAction {
240    /// A short, human-readable, title for this code action.
241    pub title: String,
242
243    /// The kind of the code action.
244    /// Used to filter code actions.
245    #[serde(skip_serializing_if = "Option::is_none")]
246    pub kind: Option<CodeActionKind>,
247
248    /// The diagnostics that this code action resolves.
249    #[serde(skip_serializing_if = "Option::is_none")]
250    pub diagnostics: Option<Vec<Diagnostic>>,
251
252    /// The workspace edit this code action performs.
253    #[serde(skip_serializing_if = "Option::is_none")]
254    pub edit: Option<WorkspaceEdit>,
255
256    /// A command this code action executes. If a code action
257    /// provides an edit and a command, first the edit is
258    /// executed and then the command.
259    #[serde(skip_serializing_if = "Option::is_none")]
260    pub command: Option<Command>,
261
262    /// Marks this as a preferred action. Preferred actions are used by the `auto fix` command and can be targeted
263    /// by keybindings.
264    /// A quick fix should be marked preferred if it properly addresses the underlying error.
265    /// A refactoring should be marked preferred if it is the most reasonable choice of actions to take.
266    ///
267    /// @since 3.15.0
268    #[serde(skip_serializing_if = "Option::is_none")]
269    pub is_preferred: Option<bool>,
270
271    /// Marks that the code action cannot currently be applied.
272    ///
273    /// Clients should follow the following guidelines regarding disabled code actions:
274    ///
275    /// - Disabled code actions are not shown in automatic
276    ///   [lightbulb](https://code.visualstudio.com/docs/editor/editingevolved#_code-action)
277    ///   code action menu.
278    ///
279    /// - Disabled actions are shown as faded out in the code action menu when the user request
280    ///   a more specific type of code action, such as refactorings.
281    ///
282    /// - If the user has a keybinding that auto applies a code action and only a disabled code
283    ///   actions are returned, the client should show the user an error message with `reason`
284    ///   in the editor.
285    ///
286    /// @since 3.16.0
287    #[serde(skip_serializing_if = "Option::is_none")]
288    pub disabled: Option<CodeActionDisabled>,
289
290    /// A data entry field that is preserved on a code action between
291    /// a `textDocument/codeAction` and a `codeAction/resolve` request.
292    ///
293    /// @since 3.16.0
294    #[serde(skip_serializing_if = "Option::is_none")]
295    pub data: Option<Value>,
296}
297
298#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
299#[serde(rename_all = "camelCase")]
300pub struct CodeActionDisabled {
301    /// Human readable description of why the code action is currently disabled.
302    ///
303    /// This is displayed in the code actions UI.
304    pub reason: String,
305}
306
307/// The reason why code actions were requested.
308///
309/// @since 3.17.0
310#[derive(Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
311#[serde(transparent)]
312pub struct CodeActionTriggerKind(i32);
313
314lsp_enum! {
315    impl CodeActionTriggerKind {
316        /// Code actions were explicitly requested by the user or by an extension.
317        const INVOKED = 1;
318
319        /// Code actions were requested automatically.
320        ///
321        /// This typically happens when current selection in a file changes, but can
322        /// also be triggered when file content changes.
323        const AUTOMATIC = 2;
324    }
325}
326
327/// Contains additional diagnostic information about the context in which
328/// a code action is run.
329#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
330#[serde(rename_all = "camelCase")]
331pub struct CodeActionContext {
332    /// An array of diagnostics.
333    pub diagnostics: Vec<Diagnostic>,
334
335    /// Requested kind of actions to return.
336    ///
337    /// Actions not of this kind are filtered out by the client before being shown. So servers
338    /// can omit computing them.
339    #[serde(skip_serializing_if = "Option::is_none")]
340    pub only: Option<Vec<CodeActionKind>>,
341
342    /// The reason why code actions were requested.
343    ///
344    /// @since 3.17.0
345    #[serde(skip_serializing_if = "Option::is_none")]
346    pub trigger_kind: Option<CodeActionTriggerKind>,
347}
348
349#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize, Default)]
350#[serde(rename_all = "camelCase")]
351pub struct CodeActionOptions {
352    /// `CodeActionKinds` that this server may return.
353    ///
354    /// The list of kinds may be generic, such as `CodeActionKind.Refactor`, or the server
355    /// may list out every specific kind they provide.
356    #[serde(skip_serializing_if = "Option::is_none")]
357    pub code_action_kinds: Option<Vec<CodeActionKind>>,
358
359    #[serde(flatten)]
360    pub work_done_progress_options: WorkDoneProgressOptions,
361
362    /// The server provides support to resolve additional
363    /// information for a code action.
364    ///
365    /// @since 3.16.0
366    #[serde(skip_serializing_if = "Option::is_none")]
367    pub resolve_provider: Option<bool>,
368}
369
370#[cfg(test)]
371mod tests {
372    use super::*;
373    use crate::tests::test_serialization;
374
375    #[test]
376    fn test_code_action_response() {
377        test_serialization(
378            &vec![
379                CodeActionOrCommand::Command(Command {
380                    title: "title".to_string(),
381                    command: "command".to_string(),
382                    arguments: None,
383                }),
384                CodeActionOrCommand::CodeAction(CodeAction {
385                    title: "title".to_string(),
386                    kind: Some(CodeActionKind::QUICKFIX),
387                    command: None,
388                    diagnostics: None,
389                    edit: None,
390                    is_preferred: None,
391                    ..CodeAction::default()
392                }),
393            ],
394            r#"[{"title":"title","command":"command"},{"title":"title","kind":"quickfix"}]"#,
395        );
396    }
397}