Rust · 21502 bytes Raw Blame History
1 //! LSP server manager
2 //!
3 //! Manages multiple language server instances, handles initialization,
4 //! and routes requests to appropriate servers.
5 //!
6 //! Note: Some methods are planned features not yet wired to the UI.
7 #![allow(dead_code)]
8
9 use anyhow::{anyhow, Result};
10 use serde_json::Value;
11 use std::collections::HashMap;
12 use std::sync::{Arc, Mutex};
13
14 use super::message::{DiagnosticsCallback, MessageHandler, ResponseCallback};
15 use super::process::ServerProcess;
16 use super::protocol::{self, LspMessage};
17 use super::types::{Capabilities, ServerConfig};
18
19 /// State of a language server
20 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
21 pub enum ServerState {
22 Starting,
23 Initializing,
24 Ready,
25 ShuttingDown,
26 Stopped,
27 }
28
29 /// A managed language server instance
30 pub struct ManagedServer {
31 pub config: ServerConfig,
32 pub process: ServerProcess,
33 pub state: ServerState,
34 pub capabilities: Capabilities,
35 pub handler: MessageHandler,
36 /// Queued didOpen notifications (for files opened before initialization)
37 pending_opens: Vec<LspMessage>,
38 }
39
40 impl ManagedServer {
41 fn new(config: ServerConfig, process: ServerProcess) -> Self {
42 Self {
43 config,
44 process,
45 state: ServerState::Starting,
46 capabilities: Capabilities::default(),
47 handler: MessageHandler::new(),
48 pending_opens: Vec::new(),
49 }
50 }
51 }
52
53 /// Manager for multiple language servers
54 pub struct LspManager {
55 /// Workspace root path
56 workspace_root: String,
57 /// Server configurations by language
58 configs: HashMap<String, Vec<ServerConfig>>,
59 /// Active servers by language
60 servers: HashMap<String, Vec<ManagedServer>>,
61 /// Global diagnostics callback
62 diagnostics_callback: Option<Arc<Mutex<DiagnosticsCallback>>>,
63 }
64
65 impl LspManager {
66 /// Create a new LSP manager
67 pub fn new(workspace_root: &str) -> Self {
68 let mut manager = Self {
69 workspace_root: workspace_root.to_string(),
70 configs: HashMap::new(),
71 servers: HashMap::new(),
72 diagnostics_callback: None,
73 };
74 manager.register_default_configs();
75 manager
76 }
77
78 /// Set the global diagnostics callback
79 pub fn set_diagnostics_callback<F>(&mut self, callback: F)
80 where
81 F: Fn(String, Vec<super::types::Diagnostic>) + Send + 'static,
82 {
83 self.diagnostics_callback = Some(Arc::new(Mutex::new(Box::new(callback))));
84 }
85
86 /// Register default server configurations
87 fn register_default_configs(&mut self) {
88 // Rust - rust-analyzer
89 self.register_config(ServerConfig::new("rust-analyzer", "rust", vec!["rust-analyzer"]));
90
91 // Python - pyright and ruff
92 self.register_config(ServerConfig::new(
93 "pyright",
94 "python",
95 vec!["pyright-langserver", "--stdio"],
96 ));
97 self.register_config(
98 ServerConfig::new("ruff", "python", vec!["ruff", "server"]).with_capabilities(
99 Capabilities {
100 completion: false,
101 hover: false,
102 definition: false,
103 references: false,
104 rename: false,
105 code_actions: true,
106 formatting: true,
107 diagnostics: true,
108 document_symbols: false,
109 workspace_symbols: false,
110 signature_help: false,
111 },
112 ),
113 );
114
115 // TypeScript/JavaScript - typescript-language-server
116 self.register_config(ServerConfig::new(
117 "typescript-language-server",
118 "typescript",
119 vec!["typescript-language-server", "--stdio"],
120 ));
121 self.register_config(ServerConfig::new(
122 "typescript-language-server",
123 "typescriptreact",
124 vec!["typescript-language-server", "--stdio"],
125 ));
126 self.register_config(ServerConfig::new(
127 "typescript-language-server",
128 "javascript",
129 vec!["typescript-language-server", "--stdio"],
130 ));
131 self.register_config(ServerConfig::new(
132 "typescript-language-server",
133 "javascriptreact",
134 vec!["typescript-language-server", "--stdio"],
135 ));
136
137 // Go - gopls
138 self.register_config(ServerConfig::new("gopls", "go", vec!["gopls"]));
139
140 // C/C++ - clangd
141 self.register_config(ServerConfig::new("clangd", "c", vec!["clangd"]));
142 self.register_config(ServerConfig::new("clangd", "cpp", vec!["clangd"]));
143
144 // Java - jdtls (Eclipse JDT Language Server)
145 self.register_config(ServerConfig::new("jdtls", "java", vec!["jdtls"]));
146
147 // Kotlin - kotlin-language-server
148 self.register_config(ServerConfig::new(
149 "kotlin-language-server",
150 "kotlin",
151 vec!["kotlin-language-server"],
152 ));
153
154 // Ruby - solargraph
155 self.register_config(ServerConfig::new(
156 "solargraph",
157 "ruby",
158 vec!["solargraph", "stdio"],
159 ));
160
161 // PHP - intelephense
162 self.register_config(ServerConfig::new(
163 "intelephense",
164 "php",
165 vec!["intelephense", "--stdio"],
166 ));
167
168 // C# - omnisharp
169 self.register_config(ServerConfig::new(
170 "omnisharp",
171 "csharp",
172 vec!["omnisharp", "--languageserver"],
173 ));
174
175 // Lua - lua-language-server
176 self.register_config(ServerConfig::new("lua-ls", "lua", vec!["lua-language-server"]));
177
178 // Zig - zls
179 self.register_config(ServerConfig::new("zls", "zig", vec!["zls"]));
180
181 // Haskell - haskell-language-server
182 self.register_config(ServerConfig::new(
183 "hls",
184 "haskell",
185 vec!["haskell-language-server-wrapper", "--lsp"],
186 ));
187
188 // OCaml - ocamllsp
189 self.register_config(ServerConfig::new("ocamllsp", "ocaml", vec!["ocamllsp"]));
190
191 // Elixir - elixir-ls
192 self.register_config(ServerConfig::new("elixir-ls", "elixir", vec!["elixir-ls"]));
193
194 // Erlang - erlang_ls
195 self.register_config(ServerConfig::new("erlang_ls", "erlang", vec!["erlang_ls"]));
196
197 // Julia - julia-ls
198 self.register_config(ServerConfig::new("julia-ls", "julia", vec!["julia", "--project=@.", "-e", "using LanguageServer; runserver()"]));
199
200 // Bash - bash-language-server
201 self.register_config(ServerConfig::new(
202 "bash-ls",
203 "shellscript",
204 vec!["bash-language-server", "start"],
205 ));
206
207 // HTML - vscode-html-language-server
208 self.register_config(ServerConfig::new(
209 "html-ls",
210 "html",
211 vec!["vscode-html-language-server", "--stdio"],
212 ));
213
214 // CSS - vscode-css-language-server
215 self.register_config(ServerConfig::new(
216 "css-ls",
217 "css",
218 vec!["vscode-css-language-server", "--stdio"],
219 ));
220
221 // JSON - vscode-json-language-server
222 self.register_config(ServerConfig::new(
223 "json-ls",
224 "json",
225 vec!["vscode-json-language-server", "--stdio"],
226 ));
227
228 // YAML - yaml-language-server
229 self.register_config(ServerConfig::new(
230 "yaml-ls",
231 "yaml",
232 vec!["yaml-language-server", "--stdio"],
233 ));
234
235 // TOML - taplo
236 self.register_config(ServerConfig::new("taplo", "toml", vec!["taplo", "lsp", "stdio"]));
237
238 // Markdown - marksman
239 self.register_config(ServerConfig::new("marksman", "markdown", vec!["marksman", "server"]));
240
241 // Docker - dockerfile-language-server
242 self.register_config(ServerConfig::new(
243 "docker-ls",
244 "dockerfile",
245 vec!["docker-langserver", "--stdio"],
246 ));
247
248 // Terraform - terraform-ls
249 self.register_config(ServerConfig::new(
250 "terraform-ls",
251 "terraform",
252 vec!["terraform-ls", "serve"],
253 ));
254
255 // Nix - nil
256 self.register_config(ServerConfig::new("nil", "nix", vec!["nil"]));
257
258 // SQL - sqls
259 self.register_config(ServerConfig::new("sqls", "sql", vec!["sqls"]));
260
261 // Vue - volar
262 self.register_config(ServerConfig::new(
263 "vue-ls",
264 "vue",
265 vec!["vue-language-server", "--stdio"],
266 ));
267
268 // Svelte - svelte-language-server
269 self.register_config(ServerConfig::new(
270 "svelte-ls",
271 "svelte",
272 vec!["svelteserver", "--stdio"],
273 ));
274
275 // Elm - elm-language-server
276 self.register_config(ServerConfig::new("elm-ls", "elm", vec!["elm-language-server"]));
277
278 // Scala - metals
279 self.register_config(ServerConfig::new("metals", "scala", vec!["metals"]));
280
281 // Dart - dart analysis server
282 self.register_config(ServerConfig::new(
283 "dart-ls",
284 "dart",
285 vec!["dart", "language-server", "--protocol=lsp"],
286 ));
287
288 // Clojure - clojure-lsp
289 self.register_config(ServerConfig::new("clojure-lsp", "clojure", vec!["clojure-lsp"]));
290
291 // Fortran - fortls
292 self.register_config(ServerConfig::new("fortls", "fortran", vec!["fortls"]));
293
294 // D - serve-d
295 self.register_config(ServerConfig::new("serve-d", "d", vec!["serve-d"]));
296
297 // Nim - nimlsp
298 self.register_config(ServerConfig::new("nimlsp", "nim", vec!["nimlsp"]));
299
300 // V - vls
301 self.register_config(ServerConfig::new("vls", "v", vec!["vls"]));
302
303 // Perl - perlnavigator
304 self.register_config(ServerConfig::new(
305 "perlnavigator",
306 "perl",
307 vec!["perlnavigator"],
308 ));
309
310 // R - languageserver
311 self.register_config(ServerConfig::new(
312 "r-ls",
313 "r",
314 vec!["R", "--slave", "-e", "languageserver::run()"],
315 ));
316
317 // GraphQL - graphql-lsp
318 self.register_config(ServerConfig::new(
319 "graphql-lsp",
320 "graphql",
321 vec!["graphql-lsp", "server", "-m", "stream"],
322 ));
323
324 // CMake - cmake-language-server
325 self.register_config(ServerConfig::new(
326 "cmake-ls",
327 "cmake",
328 vec!["cmake-language-server"],
329 ));
330
331 // Groovy - groovy-language-server
332 self.register_config(ServerConfig::new(
333 "groovy-ls",
334 "groovy",
335 vec!["groovy-language-server"],
336 ));
337
338 // Swift - sourcekit-lsp
339 self.register_config(ServerConfig::new(
340 "sourcekit-lsp",
341 "swift",
342 vec!["sourcekit-lsp"],
343 ));
344
345 // F# - fsautocomplete
346 self.register_config(ServerConfig::new(
347 "fsautocomplete",
348 "fsharp",
349 vec!["fsautocomplete", "--adaptive-lsp-server-enabled"],
350 ));
351
352 // PowerShell - PowerShellEditorServices
353 self.register_config(ServerConfig::new(
354 "pwsh-ls",
355 "powershell",
356 vec![
357 "pwsh",
358 "-NoLogo",
359 "-NoProfile",
360 "-Command",
361 "Import-Module PowerShellEditorServices; Start-EditorServices -HostName 'fackr' -HostProfileId 'fackr' -HostVersion '1.0.0' -Stdio",
362 ],
363 ));
364
365 // Protocol Buffers - buf
366 self.register_config(ServerConfig::new("buf-ls", "proto", vec!["buf", "lsp"]));
367
368 // Assembly - asm-lsp
369 self.register_config(ServerConfig::new("asm-lsp", "asm", vec!["asm-lsp"]));
370
371 // Odin - ols
372 self.register_config(ServerConfig::new("ols", "odin", vec!["ols"]));
373 }
374
375 /// Register a server configuration
376 pub fn register_config(&mut self, config: ServerConfig) {
377 self.configs
378 .entry(config.language.clone())
379 .or_default()
380 .push(config);
381 }
382
383 /// Start a server for a language
384 pub fn start_server(&mut self, language: &str) -> Result<()> {
385 let configs = self
386 .configs
387 .get(language)
388 .ok_or_else(|| anyhow!("No LSP server configured for language: {}", language))?
389 .clone();
390
391 // Start the first available server for the language
392 for config in configs {
393 match self.start_server_with_config(&config) {
394 Ok(()) => return Ok(()),
395 Err(_) => {
396 // Server not available, try next one
397 continue;
398 }
399 }
400 }
401
402 Err(anyhow!(
403 "Failed to start any LSP server for language: {}",
404 language
405 ))
406 }
407
408 /// Start all configured servers for a language
409 pub fn start_all_servers(&mut self, language: &str) -> Result<()> {
410 let configs = self
411 .configs
412 .get(language)
413 .ok_or_else(|| anyhow!("No LSP server configured for language: {}", language))?
414 .clone();
415
416 let mut started = 0;
417 for config in configs {
418 match self.start_server_with_config(&config) {
419 Ok(()) => started += 1,
420 Err(_) => {
421 // Server not available, continue
422 }
423 }
424 }
425
426 if started > 0 {
427 Ok(())
428 } else {
429 Err(anyhow!(
430 "Failed to start any LSP server for language: {}",
431 language
432 ))
433 }
434 }
435
436 /// Start a server with a specific config
437 fn start_server_with_config(&mut self, config: &ServerConfig) -> Result<()> {
438 // Check if server is already running
439 if let Some(servers) = self.servers.get(&config.language) {
440 if servers.iter().any(|s| s.config.name == config.name) {
441 return Ok(()); // Already running
442 }
443 }
444
445 // Spawn the server process
446 let process = ServerProcess::spawn(&config.command)?;
447
448 // Create managed server
449 let mut server = ManagedServer::new(config.clone(), process);
450
451 // Set up diagnostics callback if configured
452 if let Some(ref callback) = self.diagnostics_callback {
453 let cb = Arc::clone(callback);
454 server.handler.set_diagnostics_callback(Box::new(
455 move |uri, diags| {
456 if let Ok(cb) = cb.lock() {
457 cb(uri, diags);
458 }
459 },
460 ));
461 }
462
463 // Send initialize request
464 let id = protocol::next_request_id();
465 let init_msg = protocol::create_initialize_request(id, &self.workspace_root, "fackr");
466
467 server.process.send(&init_msg.to_string())?;
468 server.state = ServerState::Initializing;
469
470 // Store the server
471 self.servers
472 .entry(config.language.clone())
473 .or_default()
474 .push(server);
475
476 Ok(())
477 }
478
479 /// Get a server for a language (start if needed)
480 pub fn get_or_start_server(&mut self, language: &str) -> Result<&mut ManagedServer> {
481 if !self.servers.contains_key(language) || self.servers.get(language).map_or(true, |s| s.is_empty()) {
482 self.start_server(language)?;
483 }
484
485 self.servers
486 .get_mut(language)
487 .and_then(|servers| servers.first_mut())
488 .ok_or_else(|| anyhow!("No server available for language: {}", language))
489 }
490
491 /// Get a server with a specific capability
492 pub fn get_server_with_capability(
493 &mut self,
494 language: &str,
495 check: impl Fn(&Capabilities) -> bool,
496 ) -> Option<&mut ManagedServer> {
497 self.servers
498 .get_mut(language)?
499 .iter_mut()
500 .find(|s| s.state == ServerState::Ready && check(&s.capabilities))
501 }
502
503 /// Process messages from all servers (call this regularly)
504 pub fn process_messages(&mut self) {
505 for (_lang, servers) in self.servers.iter_mut() {
506 for server in servers.iter_mut() {
507 Self::process_server_messages(server, &self.workspace_root);
508 }
509 }
510 }
511
512 /// Process messages for a single server
513 fn process_server_messages(server: &mut ManagedServer, _workspace_root: &str) {
514 while let Some(json_str) = server.process.try_recv() {
515 if let Ok(value) = serde_json::from_str::<Value>(&json_str) {
516 if let Some(msg) = LspMessage::from_json(value.clone()) {
517 // Handle initialization response specially
518 if let LspMessage::Response { ref result, .. } = msg {
519 if server.state == ServerState::Initializing {
520 if let Some(result) = result {
521 // Parse capabilities
522 server.capabilities = protocol::parse_capabilities(result);
523 server.state = ServerState::Ready;
524
525 // Send initialized notification
526 let init_notif = protocol::create_initialized_notification();
527 let _ = server.process.send(&init_notif.to_string());
528
529 // Send any pending didOpen notifications
530 for pending in server.pending_opens.drain(..) {
531 let _ = server.process.send(&pending.to_string());
532 }
533 }
534 }
535 }
536
537 // Let the handler process the message
538 if let Some(response) = server.handler.handle_message(msg) {
539 // Send response back to server
540 let _ = server.process.send(&response.to_string());
541 }
542 }
543 }
544 }
545 }
546
547 /// Send a request to a server and register callback
548 pub fn send_request(
549 &mut self,
550 language: &str,
551 message: LspMessage,
552 callback: ResponseCallback,
553 ) -> Result<()> {
554 // Clone workspace_root to avoid borrow conflict
555 let workspace_root = self.workspace_root.clone();
556 let server = self.get_or_start_server(language)?;
557
558 // Wait for server to be ready
559 if server.state != ServerState::Ready {
560 // Process messages until ready or timeout
561 for _ in 0..50 {
562 Self::process_server_messages(server, &workspace_root);
563 if server.state == ServerState::Ready {
564 break;
565 }
566 std::thread::sleep(std::time::Duration::from_millis(100));
567 }
568 }
569
570 if let LspMessage::Request { id, .. } = &message {
571 server.handler.register_callback(*id, callback);
572 }
573
574 server.process.send(&message.to_string())?;
575 Ok(())
576 }
577
578 /// Send a notification to a server
579 pub fn send_notification(&mut self, language: &str, message: LspMessage) -> Result<()> {
580 let server = self.get_or_start_server(language)?;
581
582 // Queue didOpen if server not ready
583 if server.state != ServerState::Ready {
584 if let LspMessage::Notification { ref method, .. } = message {
585 if method == "textDocument/didOpen" {
586 server.pending_opens.push(message);
587 return Ok(());
588 }
589 }
590 }
591
592 server.process.send(&message.to_string())?;
593 Ok(())
594 }
595
596 /// Stop a server for a language
597 pub fn stop_server(&mut self, language: &str) -> Result<()> {
598 if let Some(servers) = self.servers.get_mut(language) {
599 for server in servers.iter_mut() {
600 server.state = ServerState::ShuttingDown;
601
602 // Send shutdown request
603 let id = protocol::next_request_id();
604 let shutdown = protocol::create_shutdown_request(id);
605 let _ = server.process.send(&shutdown.to_string());
606
607 // Wait briefly for shutdown acknowledgment
608 std::thread::sleep(std::time::Duration::from_millis(100));
609
610 // Send exit notification
611 let exit = protocol::create_exit_notification();
612 let _ = server.process.send(&exit.to_string());
613
614 // Kill the process
615 let _ = server.process.kill();
616 server.state = ServerState::Stopped;
617 }
618 servers.clear();
619 }
620 Ok(())
621 }
622
623 /// Stop all servers
624 pub fn stop_all(&mut self) {
625 let languages: Vec<String> = self.servers.keys().cloned().collect();
626 for lang in languages {
627 let _ = self.stop_server(&lang);
628 }
629 }
630
631 /// Check if a server is running for a language
632 pub fn has_server(&self, language: &str) -> bool {
633 self.servers
634 .get(language)
635 .map_or(false, |s| !s.is_empty() && s.iter().any(|s| s.state == ServerState::Ready))
636 }
637
638 /// Get the workspace root
639 pub fn workspace_root(&self) -> &str {
640 &self.workspace_root
641 }
642 }
643
644 impl Drop for LspManager {
645 fn drop(&mut self) {
646 self.stop_all();
647 }
648 }
649