1use crate::{
2 Command, Diagnostic, PartialResultParams, Range, TextDocumentIdentifier,
3 WorkDoneProgressOptions, WorkDoneProgressParams, WorkspaceEdit,
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 #[serde(skip_serializing_if = "Option::is_none")]
36 pub dynamic_registration: Option<bool>,
37
38 #[serde(skip_serializing_if = "Option::is_none")]
41 pub code_action_literal_support: Option<CodeActionLiteralSupport>,
42
43 #[serde(skip_serializing_if = "Option::is_none")]
47 pub is_preferred_support: Option<bool>,
48
49 #[serde(skip_serializing_if = "Option::is_none")]
53 pub disabled_support: Option<bool>,
54
55 #[serde(skip_serializing_if = "Option::is_none")]
61 pub data_support: Option<bool>,
62
63 #[serde(skip_serializing_if = "Option::is_none")]
68 pub resolve_support: Option<CodeActionCapabilityResolveSupport>,
69
70 #[serde(skip_serializing_if = "Option::is_none")]
78 pub honors_change_annotations: Option<bool>,
79}
80
81#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
86#[serde(rename_all = "camelCase")]
87pub struct CodeActionCapabilityResolveSupport {
88 pub properties: Vec<String>,
90}
91
92#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
93#[serde(rename_all = "camelCase")]
94pub struct CodeActionLiteralSupport {
95 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 pub value_set: Vec<String>,
107}
108
109#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
111#[serde(rename_all = "camelCase")]
112pub struct CodeActionParams {
113 pub text_document: TextDocumentIdentifier,
115
116 pub range: Range,
118
119 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
129pub type CodeActionResponse = Vec<CodeActionOrCommand>;
131
132#[derive(Debug, Clone, PartialEq, 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 CodeActionOrCommand::Command(command)
142 }
143}
144
145impl From<CodeAction> for CodeActionOrCommand {
146 fn from(action: CodeAction) -> Self {
147 CodeActionOrCommand::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 pub const EMPTY: CodeActionKind = CodeActionKind::new("");
157
158 pub const QUICKFIX: CodeActionKind = CodeActionKind::new("quickfix");
160
161 pub const REFACTOR: CodeActionKind = CodeActionKind::new("refactor");
163 #[cfg(feature = "proposed")]
167 pub const REFACTOR_MOVE: CodeActionKind = CodeActionKind::new("refactor.move");
168
169 #[cfg(feature = "proposed")]
173 #[allow(non_upper_case_globals)]
174 pub const RefactorMove: CodeActionKind = CodeActionKind::new("refactor.move");
175
176 pub const REFACTOR_EXTRACT: CodeActionKind = CodeActionKind::new("refactor.extract");
186
187 pub const REFACTOR_INLINE: CodeActionKind = CodeActionKind::new("refactor.inline");
196
197 pub const REFACTOR_REWRITE: CodeActionKind = CodeActionKind::new("refactor.rewrite");
208
209 pub const SOURCE: CodeActionKind = CodeActionKind::new("source");
213
214 pub const SOURCE_ORGANIZE_IMPORTS: CodeActionKind =
216 CodeActionKind::new("source.organizeImports");
217
218 pub const SOURCE_FIX_ALL: CodeActionKind = CodeActionKind::new("source.fixAll");
226
227 pub const fn new(tag: &'static str) -> Self {
228 CodeActionKind(Cow::Borrowed(tag))
229 }
230
231 pub fn as_str(&self) -> &str {
232 &self.0
233 }
234}
235
236impl From<String> for CodeActionKind {
237 fn from(from: String) -> Self {
238 CodeActionKind(Cow::from(from))
239 }
240}
241
242impl From<&'static str> for CodeActionKind {
243 fn from(from: &'static str) -> Self {
244 CodeActionKind::new(from)
245 }
246}
247
248#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
249#[serde(rename_all = "camelCase")]
250pub struct CodeAction {
251 pub title: String,
253
254 #[serde(skip_serializing_if = "Option::is_none")]
257 pub kind: Option<CodeActionKind>,
258
259 #[serde(skip_serializing_if = "Option::is_none")]
261 pub diagnostics: Option<Vec<Diagnostic>>,
262
263 #[serde(skip_serializing_if = "Option::is_none")]
265 pub edit: Option<WorkspaceEdit>,
266
267 #[serde(skip_serializing_if = "Option::is_none")]
271 pub command: Option<Command>,
272
273 #[serde(skip_serializing_if = "Option::is_none")]
280 pub is_preferred: Option<bool>,
281
282 #[serde(skip_serializing_if = "Option::is_none")]
299 pub disabled: Option<CodeActionDisabled>,
300
301 #[serde(skip_serializing_if = "Option::is_none")]
306 pub data: Option<Value>,
307
308 #[serde(skip_serializing_if = "Option::is_none")]
312 #[cfg(feature = "proposed")]
313 pub tags: Option<Vec<CodeActionTag>>,
314
315 #[serde(skip_serializing_if = "Option::is_none")]
319 pub documentation: Option<Vec<CodeActionKindDocumentation>>,
320}
321
322#[cfg(feature = "proposed")]
323#[derive(Eq, PartialEq, Clone, Copy, Deserialize, Serialize)]
324#[serde(transparent)]
325pub struct CodeActionTag(i32);
326
327#[cfg(feature = "proposed")]
328lsp_enum! {
329impl CodeActionTag {
330 pub const LLM_GENERATED: CodeActionTag = CodeActionTag(1);
331}
332}
333
334#[cfg(feature = "proposed")]
335impl CodeActionTag {
336 #[allow(non_upper_case_globals)]
337 pub const LLMGenerated: CodeActionTag = CodeActionTag::LLM_GENERATED;
338}
339
340#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
341#[serde(rename_all = "camelCase")]
342pub struct CodeActionKindDocumentation {
343 pub kind: CodeActionKind,
344 pub command: Command,
345}
346
347#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
348#[serde(rename_all = "camelCase")]
349pub struct CodeActionDisabled {
350 pub reason: String,
354}
355
356#[derive(Eq, PartialEq, Clone, Copy, Deserialize, Serialize)]
360#[serde(transparent)]
361pub struct CodeActionTriggerKind(i32);
362lsp_enum! {
363impl CodeActionTriggerKind {
364 pub const INVOKED: CodeActionTriggerKind = CodeActionTriggerKind(1);
366
367 pub const AUTOMATIC: CodeActionTriggerKind = CodeActionTriggerKind(2);
372}
373}
374
375#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
378#[serde(rename_all = "camelCase")]
379pub struct CodeActionContext {
380 pub diagnostics: Vec<Diagnostic>,
382
383 #[serde(skip_serializing_if = "Option::is_none")]
388 pub only: Option<Vec<CodeActionKind>>,
389
390 #[serde(skip_serializing_if = "Option::is_none")]
394 pub trigger_kind: Option<CodeActionTriggerKind>,
395
396 #[serde(skip_serializing_if = "Option::is_none")]
398 pub version: Option<i32>,
399}
400
401#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize, Default)]
402#[serde(rename_all = "camelCase")]
403pub struct CodeActionOptions {
404 #[serde(skip_serializing_if = "Option::is_none")]
409 pub code_action_kinds: Option<Vec<CodeActionKind>>,
410
411 #[serde(flatten)]
412 pub work_done_progress_options: WorkDoneProgressOptions,
413
414 #[serde(skip_serializing_if = "Option::is_none")]
419 pub resolve_provider: Option<bool>,
420}
421
422#[cfg(test)]
423mod tests {
424 use super::*;
425 use crate::tests::test_serialization;
426
427 #[test]
428 fn test_code_action_response() {
429 test_serialization(
430 &vec![
431 CodeActionOrCommand::Command(Command {
432 title: "title".to_string(),
433 command: "command".to_string(),
434 arguments: None,
435 }),
436 CodeActionOrCommand::CodeAction(CodeAction {
437 title: "title".to_string(),
438 kind: Some(CodeActionKind::QUICKFIX),
439 command: None,
440 diagnostics: None,
441 edit: None,
442 is_preferred: None,
443 ..CodeAction::default()
444 }),
445 ],
446 r#"[{"title":"title","command":"command"},{"title":"title","kind":"quickfix"}]"#,
447 )
448 }
449}