use anyhow::{Result, anyhow};
use std::collections::HashMap;
use std::path::PathBuf;
use std::sync::Arc;
use tokio::sync::Mutex;
use tracing::{info, warn};
use crate::config::Config;
use crate::lsp::LspClient;
pub struct ClientManager {
config: Config,
root: PathBuf,
active_clients: Mutex<HashMap<String, Arc<Mutex<LspClient>>>>,
}
impl ClientManager {
pub fn new(config: Config, root: PathBuf) -> Self {
Self {
config,
root,
active_clients: Mutex::new(HashMap::new()),
}
}
pub async fn get_client(&self, lang: &str) -> Result<Arc<Mutex<LspClient>>> {
let mut clients = self.active_clients.lock().await;
if let Some(client) = clients.get(lang) {
let is_alive = {
let c = client.lock().await;
c.is_alive()
};
if is_alive {
return Ok(client.clone());
} else {
warn!("LSP server for {} died, restarting...", lang);
clients.remove(lang);
}
}
let server_config = self.config.server.get(lang).ok_or_else(|| {
anyhow!("No LSP server configured for language '{}'", lang)
})?;
info!("Spawning LSP server for {}: {} {}", lang, server_config.command, server_config.args.join(" "));
let args: Vec<&str> = server_config.args.iter().map(|s: &String| s.as_str()).collect();
let mut client = LspClient::spawn(&server_config.command, &args).await?;
client.initialize(&self.root).await?;
let client_mutex = Arc::new(Mutex::new(client));
clients.insert(lang.to_string(), client_mutex.clone());
Ok(client_mutex)
}
pub async fn active_clients(&self) -> HashMap<String, Arc<Mutex<LspClient>>> {
self.active_clients.lock().await.clone()
}
pub async fn shutdown_client(&self, lang: &str) {
let mut clients = self.active_clients.lock().await;
if let Some(client_mutex) = clients.remove(lang) {
info!("Shutting down idle LSP server for {}", lang);
let mut client = client_mutex.lock().await;
if client.is_alive() {
if let Err(e) = client.shutdown().await {
warn!("Failed to shutdown LSP server for {}: {}", lang, e);
}
}
}
}
pub async fn shutdown_all(&self) {
let mut clients = self.active_clients.lock().await;
for (lang, client_mutex) in clients.drain() {
{
let mut client = client_mutex.lock().await;
if client.is_alive() {
if let Err(e) = client.shutdown().await {
warn!("Failed to shutdown LSP server for {}: {}", lang, e);
}
}
}
}
}
}