matrixcode_core/lsp/
registry.rs1use anyhow::Result;
6use std::collections::HashMap;
7use std::path::Path;
8use std::sync::Arc;
9use tokio::sync::RwLock;
10use tokio::time::{Duration, timeout};
11
12use super::client::LspClient;
13use super::constants::LSP_WAIT_TIMEOUT_SECS;
14use super::progress::LspProgressCallback;
15use super::types::LspServerConfig;
16
17pub struct LspClientRegistry {
19 clients: Arc<RwLock<HashMap<String, Arc<LspClient>>>>,
21}
22
23impl LspClientRegistry {
24 pub fn new() -> Self {
26 Self {
27 clients: Arc::new(RwLock::new(HashMap::new())),
28 }
29 }
30
31 pub async fn register(&self, config: &LspServerConfig, project_root: &Path) -> Result<()> {
33 let client = LspClient::from_config(config, project_root.to_path_buf());
34 client.spawn(config).await?;
35 let mut clients = self.clients.write().await;
36 clients.insert(config.language.clone(), Arc::new(client));
37 log::info!("LSP client registered for language: {}", config.language);
38 Ok(())
39 }
40
41 pub async fn register_with_progress(
60 &self,
61 config: &LspServerConfig,
62 project_root: &Path,
63 progress_callback: Arc<dyn LspProgressCallback>,
64 ) -> Result<()> {
65 let client = LspClient::from_config(config, project_root.to_path_buf());
66
67 client.spawn_async(config, progress_callback.clone()).await?;
69
70 let mut clients = self.clients.write().await;
71 clients.insert(config.language.clone(), Arc::new(client));
72 log::info!("LSP client registered for language: {}", config.language);
73 Ok(())
74 }
75
76 pub async fn get_client(&self, language: &str) -> Option<Arc<LspClient>> {
78 let clients = self.clients.read().await;
79 clients.get(language).cloned()
80 }
81
82 pub async fn get_client_or_wait(&self, language: &str) -> Result<Arc<LspClient>> {
84 if let Some(client) = self.get_client(language).await {
86 return Ok(client);
87 }
88
89 log::info!("Waiting for LSP client '{}' to start...", language);
91 let wait_duration = Duration::from_secs(LSP_WAIT_TIMEOUT_SECS);
92
93 timeout(wait_duration, async {
94 loop {
95 if let Some(client) = self.get_client(language).await {
96 log::info!("LSP client '{}' is now available", language);
97 return Ok(client);
98 }
99 tokio::time::sleep(Duration::from_millis(500)).await;
100 }
101 })
102 .await
103 .map_err(|_| anyhow::anyhow!(
104 "LSP 客户端 '{}' 启动超时({}秒)。\n\
105 提示:LSP 服务器可能正在后台启动,请稍后再试。\n\
106 状态:检查 TUI 状态栏 LSP 是否显示 'starting...'",
107 language, LSP_WAIT_TIMEOUT_SECS
108 ))?
109 }
110
111 pub async fn has_active_clients(&self) -> bool {
113 let clients = self.clients.read().await;
114 !clients.is_empty()
115 }
116
117 pub async fn active_languages(&self) -> Vec<String> {
119 let clients = self.clients.read().await;
120 clients.keys().cloned().collect()
121 }
122
123 pub async fn shutdown_all(&self) -> Result<()> {
125 let mut clients = self.clients.write().await;
126 for (language, client) in clients.iter() {
127 if let Err(e) = client.shutdown().await {
128 log::warn!("Failed to shutdown LSP client '{}': {}", language, e);
129 }
130 }
131 clients.clear();
132 Ok(())
133 }
134}
135
136impl Default for LspClientRegistry {
137 fn default() -> Self {
138 Self::new()
139 }
140}