Skip to main content

spring_lsp/
index.rs

1//! 索引管理模块
2//!
3//! 提供项目级别的索引管理,包括符号索引、路由索引和组件索引。
4//! 使用并发安全的数据结构支持多线程访问。
5
6use dashmap::DashMap;
7use lsp_types::{Location, Url};
8use std::sync::{Arc, RwLock};
9
10/// 符号信息
11#[derive(Debug, Clone)]
12pub struct SymbolInfo {
13    /// 符号名称
14    pub name: String,
15    /// 符号类型
16    pub symbol_type: SymbolType,
17    /// 位置
18    pub location: Location,
19}
20
21/// 符号类型
22#[derive(Debug, Clone, PartialEq, Eq)]
23pub enum SymbolType {
24    /// 结构体
25    Struct,
26    /// 函数
27    Function,
28    /// 常量
29    Const,
30    /// 静态变量
31    Static,
32    /// 模块
33    Module,
34}
35
36/// 符号索引
37#[derive(Debug, Clone)]
38pub struct SymbolIndex {
39    /// 符号映射(内部使用 DashMap 提供并发安全)
40    pub symbols: DashMap<String, Vec<SymbolInfo>>,
41}
42
43impl SymbolIndex {
44    /// 创建新的符号索引
45    pub fn new() -> Self {
46        Self {
47            symbols: DashMap::new(),
48        }
49    }
50
51    /// 添加符号
52    pub fn add(&self, name: String, info: SymbolInfo) {
53        self.symbols.entry(name).or_default().push(info);
54    }
55
56    /// 查找符号
57    pub fn find(&self, name: &str) -> Vec<SymbolInfo> {
58        self.symbols
59            .get(name)
60            .map(|v| v.clone())
61            .unwrap_or_default()
62    }
63
64    /// 清空索引
65    pub fn clear(&self) {
66        self.symbols.clear();
67    }
68}
69
70impl Default for SymbolIndex {
71    fn default() -> Self {
72        Self::new()
73    }
74}
75
76/// 组件信息
77#[derive(Debug, Clone)]
78pub struct ComponentInfo {
79    /// 组件名称
80    pub name: String,
81    /// 类型名称
82    pub type_name: String,
83    /// 位置
84    pub location: Location,
85    /// 所属插件
86    pub plugin: Option<String>,
87}
88
89/// 组件索引
90#[derive(Debug, Clone)]
91pub struct ComponentIndex {
92    /// 组件映射(内部使用 DashMap 提供并发安全)
93    pub components: DashMap<String, ComponentInfo>,
94}
95
96impl ComponentIndex {
97    /// 创建新的组件索引
98    pub fn new() -> Self {
99        Self {
100            components: DashMap::new(),
101        }
102    }
103
104    /// 添加组件
105    pub fn add(&self, name: String, info: ComponentInfo) {
106        self.components.insert(name, info);
107    }
108
109    /// 查找组件
110    pub fn find(&self, name: &str) -> Option<ComponentInfo> {
111        self.components.get(name).map(|v| v.clone())
112    }
113
114    /// 清空索引
115    pub fn clear(&self) {
116        self.components.clear();
117    }
118}
119
120impl Default for ComponentIndex {
121    fn default() -> Self {
122        Self::new()
123    }
124}
125
126/// 工作空间信息
127pub struct Workspace {
128    /// 根目录 URI
129    pub root_uri: Url,
130    /// 文档列表
131    pub documents: Vec<(Url, String)>,
132}
133
134/// 索引管理器
135///
136/// 管理项目级别的索引,包括符号索引、路由索引和组件索引。
137/// 使用 RwLock 保护索引结构,因为重建索引时需要整体替换。
138pub struct IndexManager {
139    /// 符号索引(使用 RwLock 因为重建时需要整体替换)
140    symbol_index: Arc<RwLock<SymbolIndex>>,
141    /// 路由索引
142    route_index: Arc<RwLock<crate::route::RouteIndex>>,
143    /// 组件索引
144    component_index: Arc<RwLock<ComponentIndex>>,
145}
146
147impl IndexManager {
148    /// 创建新的索引管理器
149    pub fn new() -> Self {
150        Self {
151            symbol_index: Arc::new(RwLock::new(SymbolIndex::new())),
152            route_index: Arc::new(RwLock::new(crate::route::RouteIndex::new())),
153            component_index: Arc::new(RwLock::new(ComponentIndex::new())),
154        }
155    }
156
157    /// 构建索引(异步,可能耗时)
158    ///
159    /// 在后台线程构建索引,完成后原子性地替换整个索引。
160    /// 这确保读取者看到的是完整的旧索引或完整的新索引,而不会看到中间状态。
161    pub async fn build(&self, workspace: &Workspace) {
162        let symbol_index = self.symbol_index.clone();
163        let route_index = self.route_index.clone();
164        let component_index = self.component_index.clone();
165
166        // 克隆工作空间数据以便在异步任务中使用
167        let root_uri = workspace.root_uri.clone();
168        let documents = workspace.documents.clone();
169
170        tokio::spawn(async move {
171            // 构建新索引(不持有锁)
172            let new_symbols = Self::build_symbol_index(&root_uri, &documents).await;
173            let new_routes = Self::build_route_index(&root_uri, &documents).await;
174            let new_components = Self::build_component_index(&root_uri, &documents).await;
175
176            // 原子性地替换整个索引(短暂持有写锁)
177            *symbol_index
178                .write()
179                .expect("Failed to acquire write lock on symbol index") = new_symbols;
180            *route_index
181                .write()
182                .expect("Failed to acquire write lock on route index") = new_routes;
183            *component_index
184                .write()
185                .expect("Failed to acquire write lock on component index") = new_components;
186
187            tracing::info!("Index rebuild completed");
188        });
189    }
190
191    /// 增量更新索引
192    ///
193    /// 当单个文档发生变化时,只更新该文档相关的索引条目。
194    pub fn update(&self, uri: &Url, _content: &str) {
195        // 解析文档并更新索引
196        // 这里简化实现,实际应该解析文档并提取符号、路由和组件信息
197
198        tracing::debug!("Updating index for {}", uri);
199
200        // TODO: 实现增量更新逻辑
201        // 1. 解析文档
202        // 2. 提取符号、路由和组件
203        // 3. 更新对应的索引
204    }
205
206    /// 查找符号
207    pub fn find_symbol(&self, name: &str) -> Vec<SymbolInfo> {
208        let index = self
209            .symbol_index
210            .read()
211            .expect("Failed to acquire read lock on symbol index");
212        index.find(name)
213    }
214
215    /// 查找组件
216    pub fn find_component(&self, name: &str) -> Option<ComponentInfo> {
217        let index = self
218            .component_index
219            .read()
220            .expect("Failed to acquire read lock on component index");
221        index.find(name)
222    }
223
224    /// 获取所有路由
225    pub fn get_all_routes(&self) -> Vec<crate::route::RouteInfo> {
226        let index = self
227            .route_index
228            .read()
229            .expect("Failed to acquire read lock on route index");
230        index.routes.clone()
231    }
232
233    /// 构建符号索引(内部方法)
234    async fn build_symbol_index(_root_uri: &Url, _documents: &[(Url, String)]) -> SymbolIndex {
235        // TODO: 实现符号索引构建
236        // 1. 遍历所有 Rust 文件
237        // 2. 解析语法树
238        // 3. 提取符号信息
239        SymbolIndex::new()
240    }
241
242    /// 构建路由索引(内部方法)
243    async fn build_route_index(
244        _root_uri: &Url,
245        _documents: &[(Url, String)],
246    ) -> crate::route::RouteIndex {
247        // TODO: 实现路由索引构建
248        // 1. 遍历所有 Rust 文件
249        // 2. 识别路由宏
250        // 3. 构建路由索引
251        crate::route::RouteIndex::new()
252    }
253
254    /// 构建组件索引(内部方法)
255    async fn build_component_index(
256        _root_uri: &Url,
257        _documents: &[(Url, String)],
258    ) -> ComponentIndex {
259        // TODO: 实现组件索引构建
260        // 1. 遍历所有 Rust 文件
261        // 2. 识别 #[derive(Service)] 和组件注册
262        // 3. 构建组件索引
263        ComponentIndex::new()
264    }
265}
266
267impl Default for IndexManager {
268    fn default() -> Self {
269        Self::new()
270    }
271}