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}