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