|
1 | | -use std::str::FromStr; |
2 | | - |
3 | | -use log::error; |
4 | 1 | use serde::Deserialize; |
5 | | -use tower_lsp_server::{ |
6 | | - jsonrpc::{self, Error}, |
7 | | - lsp_types::{ |
8 | | - ApplyWorkspaceEditParams, TextEdit, Uri, WorkspaceEdit, request::ApplyWorkspaceEdit, |
9 | | - }, |
10 | | -}; |
11 | | - |
12 | | -use crate::{Backend, capabilities::Capabilities}; |
13 | | - |
14 | | -pub const LSP_COMMANDS: [WorkspaceCommands; 1] = [WorkspaceCommands::FixAll(FixAllCommand)]; |
15 | | - |
16 | | -pub trait WorkspaceCommand { |
17 | | - fn command_id(&self) -> String; |
18 | | - fn available(&self, cap: Capabilities) -> bool; |
19 | | - type CommandArgs<'a>: serde::Deserialize<'a>; |
20 | | - async fn execute( |
21 | | - &self, |
22 | | - backend: &Backend, |
23 | | - args: Self::CommandArgs<'_>, |
24 | | - ) -> jsonrpc::Result<Option<serde_json::Value>>; |
25 | | -} |
26 | | - |
27 | | -pub enum WorkspaceCommands { |
28 | | - FixAll(FixAllCommand), |
29 | | -} |
30 | | - |
31 | | -impl WorkspaceCommands { |
32 | | - pub fn command_id(&self) -> String { |
33 | | - match self { |
34 | | - WorkspaceCommands::FixAll(c) => c.command_id(), |
35 | | - } |
36 | | - } |
37 | | - pub fn available(&self, cap: Capabilities) -> bool { |
38 | | - match self { |
39 | | - WorkspaceCommands::FixAll(c) => c.available(cap), |
40 | | - } |
41 | | - } |
42 | | - pub async fn execute( |
43 | | - &self, |
44 | | - backend: &Backend, |
45 | | - args: Vec<serde_json::Value>, |
46 | | - ) -> jsonrpc::Result<Option<serde_json::Value>> { |
47 | | - match self { |
48 | | - WorkspaceCommands::FixAll(c) => { |
49 | | - let arg: Result< |
50 | | - <FixAllCommand as WorkspaceCommand>::CommandArgs<'_>, |
51 | | - serde_json::Error, |
52 | | - > = serde_json::from_value(serde_json::Value::Array(args)); |
53 | | - if let Err(e) = arg { |
54 | | - error!("Invalid args passed to {:?}: {e}", c.command_id()); |
55 | | - return Err(Error::invalid_request()); |
56 | | - } |
57 | | - let arg = arg.unwrap(); |
58 | | - |
59 | | - c.execute(backend, arg).await |
60 | | - } |
61 | | - } |
62 | | - } |
63 | | -} |
64 | 2 |
|
65 | | -pub struct FixAllCommand; |
| 3 | +pub const FIX_ALL_COMMAND_ID: &str = "oxc.fixAll"; |
66 | 4 |
|
67 | 5 | #[derive(Deserialize)] |
68 | | -pub struct FixAllCommandArg { |
69 | | - uri: String, |
| 6 | +pub struct FixAllCommandArgs { |
| 7 | + pub uri: String, |
70 | 8 | } |
71 | 9 |
|
72 | | -impl WorkspaceCommand for FixAllCommand { |
73 | | - fn command_id(&self) -> String { |
74 | | - "oxc.fixAll".into() |
75 | | - } |
76 | | - fn available(&self, cap: Capabilities) -> bool { |
77 | | - cap.workspace_apply_edit |
78 | | - } |
79 | | - type CommandArgs<'a> = (FixAllCommandArg,); |
80 | | - |
81 | | - async fn execute( |
82 | | - &self, |
83 | | - backend: &Backend, |
84 | | - args: Self::CommandArgs<'_>, |
85 | | - ) -> jsonrpc::Result<Option<serde_json::Value>> { |
86 | | - let url = Uri::from_str(&args.0.uri); |
87 | | - if let Err(e) = url { |
88 | | - error!("Invalid uri passed to {:?}: {e}", self.command_id()); |
89 | | - return Err(Error::invalid_request()); |
90 | | - } |
91 | | - let url = url.unwrap(); |
| 10 | +impl TryFrom<Vec<serde_json::Value>> for FixAllCommandArgs { |
| 11 | + type Error = &'static str; |
92 | 12 |
|
93 | | - let mut edits = vec![]; |
94 | | - if let Some(value) = backend.diagnostics_report_map.pin_owned().get(&url.to_string()) { |
95 | | - for report in value { |
96 | | - if let Some(fixed) = &report.fixed_content { |
97 | | - edits.push(TextEdit { range: fixed.range, new_text: fixed.code.clone() }); |
98 | | - } |
99 | | - } |
100 | | - let _ = backend |
101 | | - .client |
102 | | - .send_request::<ApplyWorkspaceEdit>(ApplyWorkspaceEditParams { |
103 | | - label: Some(match edits.len() { |
104 | | - 1 => "Oxlint: 1 fix applied".into(), |
105 | | - n => format!("Oxlint: {n} fixes applied"), |
106 | | - }), |
107 | | - edit: WorkspaceEdit { |
108 | | - #[expect(clippy::disallowed_types)] |
109 | | - changes: Some(std::collections::HashMap::from([(url, edits)])), |
110 | | - ..WorkspaceEdit::default() |
111 | | - }, |
112 | | - }) |
113 | | - .await; |
| 13 | + fn try_from(value: Vec<serde_json::Value>) -> Result<Self, Self::Error> { |
| 14 | + if value.len() != 1 { |
| 15 | + return Err("Expected exactly one argument for FixAllCommandArgs"); |
114 | 16 | } |
115 | 17 |
|
116 | | - Ok(None) |
| 18 | + let first_value = value.into_iter().next().ok_or("Missing argument")?; |
| 19 | + serde_json::from_value(first_value).map_err(|_| "Failed to parse FixAllCommandArgs") |
117 | 20 | } |
118 | 21 | } |
0 commit comments