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
164 pub const REFACTOR_EXTRACT: CodeActionKind = CodeActionKind::new("refactor.extract");
174
175 pub const REFACTOR_INLINE: CodeActionKind = CodeActionKind::new("refactor.inline");
184
185 pub const REFACTOR_REWRITE: CodeActionKind = CodeActionKind::new("refactor.rewrite");
196
197 pub const SOURCE: CodeActionKind = CodeActionKind::new("source");
201
202 pub const SOURCE_ORGANIZE_IMPORTS: CodeActionKind =
204 CodeActionKind::new("source.organizeImports");
205
206 pub const SOURCE_FIX_ALL: CodeActionKind = CodeActionKind::new("source.fixAll");
214
215 pub const fn new(tag: &'static str) -> Self {
216 CodeActionKind(Cow::Borrowed(tag))
217 }
218
219 pub fn as_str(&self) -> &str {
220 &self.0
221 }
222}
223
224impl From<String> for CodeActionKind {
225 fn from(from: String) -> Self {
226 CodeActionKind(Cow::from(from))
227 }
228}
229
230impl From<&'static str> for CodeActionKind {
231 fn from(from: &'static str) -> Self {
232 CodeActionKind::new(from)
233 }
234}
235
236#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
237#[serde(rename_all = "camelCase")]
238pub struct CodeAction {
239 pub title: String,
241
242 #[serde(skip_serializing_if = "Option::is_none")]
245 pub kind: Option<CodeActionKind>,
246
247 #[serde(skip_serializing_if = "Option::is_none")]
249 pub diagnostics: Option<Vec<Diagnostic>>,
250
251 #[serde(skip_serializing_if = "Option::is_none")]
253 pub edit: Option<WorkspaceEdit>,
254
255 #[serde(skip_serializing_if = "Option::is_none")]
259 pub command: Option<Command>,
260
261 #[serde(skip_serializing_if = "Option::is_none")]
268 pub is_preferred: Option<bool>,
269
270 #[serde(skip_serializing_if = "Option::is_none")]
287 pub disabled: Option<CodeActionDisabled>,
288
289 #[serde(skip_serializing_if = "Option::is_none")]
294 pub data: Option<Value>,
295}
296
297#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
298#[serde(rename_all = "camelCase")]
299pub struct CodeActionDisabled {
300 pub reason: String,
304}
305
306#[derive(Eq, PartialEq, Clone, Copy, Deserialize, Serialize)]
310#[serde(transparent)]
311pub struct CodeActionTriggerKind(i32);
312lsp_enum! {
313impl CodeActionTriggerKind {
314 pub const INVOKED: CodeActionTriggerKind = CodeActionTriggerKind(1);
316
317 pub const AUTOMATIC: CodeActionTriggerKind = CodeActionTriggerKind(2);
322}
323}
324
325#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
328#[serde(rename_all = "camelCase")]
329pub struct CodeActionContext {
330 pub diagnostics: Vec<Diagnostic>,
332
333 #[serde(skip_serializing_if = "Option::is_none")]
338 pub only: Option<Vec<CodeActionKind>>,
339
340 #[serde(skip_serializing_if = "Option::is_none")]
344 pub trigger_kind: Option<CodeActionTriggerKind>,
345}
346
347#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize, Default)]
348#[serde(rename_all = "camelCase")]
349pub struct CodeActionOptions {
350 #[serde(skip_serializing_if = "Option::is_none")]
355 pub code_action_kinds: Option<Vec<CodeActionKind>>,
356
357 #[serde(flatten)]
358 pub work_done_progress_options: WorkDoneProgressOptions,
359
360 #[serde(skip_serializing_if = "Option::is_none")]
365 pub resolve_provider: Option<bool>,
366}
367
368#[cfg(test)]
369mod tests {
370 use super::*;
371 use crate::tests::test_serialization;
372
373 #[test]
374 fn test_code_action_response() {
375 test_serialization(
376 &vec![
377 CodeActionOrCommand::Command(Command {
378 title: "title".to_string(),
379 command: "command".to_string(),
380 arguments: None,
381 }),
382 CodeActionOrCommand::CodeAction(CodeAction {
383 title: "title".to_string(),
384 kind: Some(CodeActionKind::QUICKFIX),
385 command: None,
386 diagnostics: None,
387 edit: None,
388 is_preferred: None,
389 ..CodeAction::default()
390 }),
391 ],
392 r#"[{"title":"title","command":"command"},{"title":"title","kind":"quickfix"}]"#,
393 )
394 }
395}