1use serde::{Deserialize, Serialize};
6use std::collections::HashMap;
7use std::path::Path;
8use std::process::Stdio;
9use std::sync::atomic::{AtomicU64, Ordering};
10use std::sync::Arc;
11use tokio::process::{Child, Command};
12use tokio::sync::{mpsc, RwLock};
13
14use super::config::LSPServerConfig;
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
18pub enum LSPServerState {
19 Initializing,
20 Ready,
21 Error,
22 Stopped,
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize)]
27pub struct LSPDiagnostic {
28 pub range: LSPRange,
29 pub severity: Option<u32>,
30 pub message: String,
31 pub source: Option<String>,
32 pub code: Option<String>,
33}
34
35#[derive(Debug, Clone, Serialize, Deserialize)]
37pub struct LSPRange {
38 pub start: LSPPosition,
39 pub end: LSPPosition,
40}
41
42#[derive(Debug, Clone, Serialize, Deserialize)]
44pub struct LSPPosition {
45 pub line: u32,
46 pub character: u32,
47}
48
49#[derive(Debug, Clone)]
51struct OpenDocument {
52 uri: String,
53 language_id: String,
54 version: u32,
55 content: String,
56}
57
58pub struct LSPServer {
60 config: LSPServerConfig,
61 state: Arc<RwLock<LSPServerState>>,
62 process: Arc<RwLock<Option<Child>>>,
63 next_request_id: AtomicU64,
64 open_documents: Arc<RwLock<HashMap<String, OpenDocument>>>,
65 workspace_root: Arc<RwLock<String>>,
66 restart_count: Arc<RwLock<u32>>,
67 request_tx: Option<mpsc::Sender<String>>,
68}
69
70impl LSPServer {
71 pub fn new(config: LSPServerConfig) -> Self {
73 Self {
74 config,
75 state: Arc::new(RwLock::new(LSPServerState::Stopped)),
76 process: Arc::new(RwLock::new(None)),
77 next_request_id: AtomicU64::new(1),
78 open_documents: Arc::new(RwLock::new(HashMap::new())),
79 workspace_root: Arc::new(RwLock::new(String::new())),
80 restart_count: Arc::new(RwLock::new(0)),
81 request_tx: None,
82 }
83 }
84
85 pub async fn start(&mut self, workspace_root: &Path) -> Result<(), String> {
87 let mut state = self.state.write().await;
88 if *state != LSPServerState::Stopped {
89 return Err(format!("服务器已启动 (状态: {:?})", *state));
90 }
91
92 *state = LSPServerState::Initializing;
93 *self.workspace_root.write().await = workspace_root.display().to_string();
94
95 let mut cmd = Command::new(&self.config.command);
97 cmd.args(&self.config.args)
98 .current_dir(workspace_root)
99 .stdin(Stdio::piped())
100 .stdout(Stdio::piped())
101 .stderr(Stdio::piped());
102
103 for (key, value) in &self.config.env {
105 cmd.env(key, value);
106 }
107
108 match cmd.spawn() {
109 Ok(child) => {
110 *self.process.write().await = Some(child);
111 *state = LSPServerState::Ready;
112 tracing::info!("[LSP] {} 启动成功", self.config.name);
113 Ok(())
114 }
115 Err(e) => {
116 *state = LSPServerState::Error;
117 Err(format!("启动 {} 失败: {}", self.config.name, e))
118 }
119 }
120 }
121
122 pub async fn stop(&mut self) -> Result<(), String> {
124 let mut state = self.state.write().await;
125 if *state == LSPServerState::Stopped {
126 return Ok(());
127 }
128
129 if let Some(mut child) = self.process.write().await.take() {
131 let _ = child.kill().await;
132 }
133
134 *state = LSPServerState::Stopped;
135 tracing::info!("[LSP] {} 已停止", self.config.name);
136 Ok(())
137 }
138
139 pub async fn get_state(&self) -> LSPServerState {
141 *self.state.read().await
142 }
143
144 pub fn get_config(&self) -> &LSPServerConfig {
146 &self.config
147 }
148
149 pub async fn is_healthy(&self) -> bool {
151 *self.state.read().await == LSPServerState::Ready
152 }
153
154 pub async fn get_restart_count(&self) -> u32 {
156 *self.restart_count.read().await
157 }
158
159 pub async fn open_document(&self, file_path: &Path, content: &str, language_id: &str) {
161 let uri = format!("file://{}", file_path.display());
162 let doc = OpenDocument {
163 uri: uri.clone(),
164 language_id: language_id.to_string(),
165 version: 1,
166 content: content.to_string(),
167 };
168 self.open_documents
169 .write()
170 .await
171 .insert(file_path.display().to_string(), doc);
172 }
173
174 pub async fn close_document(&self, file_path: &Path) {
176 self.open_documents
177 .write()
178 .await
179 .remove(&file_path.display().to_string());
180 }
181
182 pub async fn is_document_open(&self, file_path: &Path) -> bool {
184 self.open_documents
185 .read()
186 .await
187 .contains_key(&file_path.display().to_string())
188 }
189
190 fn next_id(&self) -> u64 {
192 self.next_request_id.fetch_add(1, Ordering::SeqCst)
193 }
194}