Skip to main content

summer_lsp/analysis/completion/
engine_impl.rs

1//! 智能补全引擎模块
2
3use lsp_types::{
4    CompletionItem, CompletionItemKind, Documentation, InsertTextFormat, MarkupContent, MarkupKind,
5    Position, Range,
6};
7
8use crate::analysis::rust::macro_analyzer::SummerMacro;
9use crate::analysis::toml::toml_analyzer::{TomlAnalyzer, TomlDocument};
10use crate::core::schema::SchemaProvider;
11
12/// 补全上下文
13///
14/// 提供补全请求的上下文信息,用于确定补全类型
15#[derive(Debug, Clone)]
16pub enum CompletionContext {
17    /// TOML 配置文件补全
18    Toml,
19    /// Rust 宏补全
20    Macro,
21    /// 未知上下文
22    Unknown,
23}
24
25/// 补全引擎
26///
27/// 提供智能补全功能,支持 TOML 配置文件和 Rust 宏的补全
28pub struct CompletionEngine {
29    /// TOML 分析器
30    toml_analyzer: TomlAnalyzer,
31}
32
33impl CompletionEngine {
34    /// 创建新的补全引擎
35    ///
36    /// # 参数
37    ///
38    /// * `schema_provider` - Schema 提供者,用于 TOML 配置补全
39    pub fn new(schema_provider: SchemaProvider) -> Self {
40        Self {
41            toml_analyzer: TomlAnalyzer::new(schema_provider),
42        }
43    }
44
45    /// 提供补全
46    ///
47    /// 根据文档类型和位置提供相应的补全项
48    ///
49    /// # 参数
50    ///
51    /// * `context` - 补全上下文,指示补全类型
52    /// * `position` - 光标位置
53    /// * `toml_doc` - TOML 文档(可选,用于 TOML 补全)
54    /// * `macro_info` - 宏信息(可选,用于宏补全)
55    ///
56    /// # 返回
57    ///
58    /// 补全项列表
59    pub fn complete(
60        &self,
61        context: CompletionContext,
62        position: Position,
63        toml_doc: Option<&TomlDocument>,
64        macro_info: Option<&SummerMacro>,
65    ) -> Vec<CompletionItem> {
66        match context {
67            CompletionContext::Toml => {
68                if let Some(doc) = toml_doc {
69                    self.complete_toml(doc, position)
70                } else {
71                    Vec::new()
72                }
73            }
74            CompletionContext::Macro => {
75                if let Some(macro_info) = macro_info {
76                    self.complete_macro(macro_info, None)
77                } else {
78                    Vec::new()
79                }
80            }
81            CompletionContext::Unknown => Vec::new(),
82        }
83    }
84
85    /// TOML 配置补全(公共方法)
86    ///
87    /// 为 TOML 配置文件提供补全,支持:
88    /// - 配置前缀补全(在 `[` 后)
89    /// - 配置项补全(在配置节内)
90    /// - 枚举值补全
91    /// - 环境变量补全(在 `${` 后)
92    ///
93    /// # 参数
94    ///
95    /// * `doc` - TOML 文档
96    /// * `position` - 光标位置
97    ///
98    /// # 返回
99    ///
100    /// 补全项列表
101    pub fn complete_toml_document(
102        &self,
103        doc: &TomlDocument,
104        position: Position,
105    ) -> Vec<CompletionItem> {
106        self.complete_toml(doc, position)
107    }
108
109    /// TOML 配置补全(内部方法)
110    ///
111    /// 为 TOML 配置文件提供补全,支持:
112    /// - 配置前缀补全(在 `[` 后)
113    /// - 配置项补全(在配置节内)
114    /// - 枚举值补全
115    /// - 环境变量补全(在 `${` 后)
116    ///
117    /// # 参数
118    ///
119    /// * `doc` - TOML 文档
120    /// * `position` - 光标位置
121    ///
122    /// # 返回
123    ///
124    /// 补全项列表
125    fn complete_toml(&self, doc: &TomlDocument, position: Position) -> Vec<CompletionItem> {
126        // 1. 检查是否在配置前缀位置([之后)
127        if self.is_prefix_position(doc, position) {
128            return self.complete_config_prefix();
129        }
130
131        // 2. 检查是否在环境变量位置(${之后)
132        if self.is_env_var_position(doc, position) {
133            return self.complete_env_var();
134        }
135
136        // 3. 检查是否在配置节内
137        if let Some(section) = self.find_section_at_position(doc, position) {
138            // 3.1 检查是否在属性值位置,需要补全枚举值
139            if let Some(property_name) = self.find_property_at_position(section, position) {
140                // 获取属性的 Schema 信息
141                let schema_provider = self.toml_analyzer.schema_provider();
142                if let Some(plugin_schema) = schema_provider.get_plugin(&section.prefix) {
143                    if let Some(property_schema) = plugin_schema.properties.get(&property_name) {
144                        // 检查是否有枚举值
145                        if let crate::schema::TypeInfo::String {
146                            enum_values: Some(enum_vals),
147                            ..
148                        } = &property_schema.type_info
149                        {
150                            return self.complete_enum_values(enum_vals);
151                        }
152                    }
153                }
154            }
155
156            // 3.2 否则提供配置项补全
157            return self.complete_config_properties(section);
158        }
159
160        Vec::new()
161    }
162
163    /// 检查是否在配置前缀位置
164    ///
165    /// 判断光标是否在 `[` 字符之后,需要补全配置前缀
166    fn is_prefix_position(&self, doc: &TomlDocument, position: Position) -> bool {
167        // 获取光标所在行的内容
168        let lines: Vec<&str> = doc.content.lines().collect();
169
170        if position.line as usize >= lines.len() {
171            return false;
172        }
173
174        let line = lines[position.line as usize];
175        let char_pos = position.character as usize;
176
177        // 光标位置必须在行内或行尾
178        if char_pos > line.len() {
179            return false;
180        }
181
182        // 检查光标前的字符
183        let before_cursor = if char_pos > 0 { &line[..char_pos] } else { "" };
184
185        // 如果光标前是 `[` 或 `[` 后跟一些字符,则认为是前缀位置
186        // 但必须确保还没有闭合括号
187        let trimmed = before_cursor.trim_start();
188
189        // 只有在输入 `[` 后且还没有完成节名输入时才提供前缀补全
190        // 如果已经有完整的节名(包含 `]`),则不是前缀位置
191        trimmed.starts_with('[') && !trimmed.contains(']') && !line.contains(']')
192    }
193
194    /// 检查是否在环境变量位置
195    ///
196    /// 判断光标是否在 `${` 之后,需要补全环境变量名
197    fn is_env_var_position(&self, _doc: &TomlDocument, _position: Position) -> bool {
198        // 简化实现:这里需要检查光标前的字符是否是 `${`
199        // 在实际实现中,应该解析文档内容来判断
200        false
201    }
202
203    /// 查找光标所在的配置节
204    ///
205    /// 根据光标位置查找对应的配置节
206    fn find_section_at_position<'a>(
207        &self,
208        doc: &'a TomlDocument,
209        position: Position,
210    ) -> Option<&'a crate::toml_analyzer::ConfigSection> {
211        doc.config_sections
212            .values()
213            .find(|&section| self.position_in_range(position, section.range))
214    }
215
216    /// 查找光标所在的属性名
217    ///
218    /// 在配置节中查找光标位置对应的属性名(用于枚举值补全)
219    fn find_property_at_position(
220        &self,
221        section: &crate::toml_analyzer::ConfigSection,
222        position: Position,
223    ) -> Option<String> {
224        for (key, property) in &section.properties {
225            // 检查位置是否在属性值范围内
226            if self.position_in_range(position, property.range) {
227                return Some(key.clone());
228            }
229        }
230        None
231    }
232
233    /// 检查位置是否在范围内
234    fn position_in_range(&self, position: Position, range: Range) -> bool {
235        if position.line < range.start.line || position.line > range.end.line {
236            return false;
237        }
238        if position.line == range.start.line && position.character < range.start.character {
239            return false;
240        }
241        if position.line == range.end.line && position.character > range.end.character {
242            return false;
243        }
244        true
245    }
246
247    /// 补全配置前缀
248    ///
249    /// 提供所有可用的配置前缀(插件名称)
250    fn complete_config_prefix(&self) -> Vec<CompletionItem> {
251        let prefixes = self.toml_analyzer.schema_provider().get_all_prefixes();
252
253        prefixes
254            .into_iter()
255            .map(|prefix: String| {
256                let description = format!("{} 插件配置", prefix);
257
258                CompletionItem {
259                    label: prefix.clone(),
260                    kind: Some(CompletionItemKind::MODULE),
261                    detail: Some(format!("[{}] 配置节", prefix)),
262                    documentation: Some(Documentation::MarkupContent(MarkupContent {
263                        kind: MarkupKind::Markdown,
264                        value: format!(
265                            "**{}** 插件配置节\n\n{}\n\n\
266                             **使用方式**:\n\
267                             ```toml\n\
268                             [{}]\n\
269                             # 配置项...\n\
270                             ```",
271                            prefix, description, prefix
272                        ),
273                    })),
274                    insert_text: Some(format!("[{}]\n", prefix)),
275                    insert_text_format: Some(lsp_types::InsertTextFormat::SNIPPET),
276                    ..Default::default()
277                }
278            })
279            .collect()
280    }
281
282    /// 补全配置项
283    ///
284    /// 在配置节内提供配置项补全,自动去重已存在的配置项
285    /// 补全配置项
286    ///
287    /// 在配置节内提供配置项补全,自动去重已存在的配置项
288    fn complete_config_properties(
289        &self,
290        section: &crate::toml_analyzer::ConfigSection,
291    ) -> Vec<CompletionItem> {
292        let prefix = &section.prefix;
293
294        // 从 Schema Provider 中获取插件信息
295        let schema_provider = self.toml_analyzer.schema_provider();
296        let plugin_schema = match schema_provider.get_plugin(prefix) {
297            Some(schema) => schema,
298            None => return Vec::new(),
299        };
300
301        // 获取已存在的属性名(用于去重)
302        let existing_keys: std::collections::HashSet<String> =
303            section.properties.keys().cloned().collect();
304
305        // 为每个未使用的属性创建补全项
306        let mut completions = Vec::new();
307
308        for (key, property_schema) in &plugin_schema.properties {
309            // 跳过已存在的属性
310            if existing_keys.contains(key) {
311                continue;
312            }
313
314            // 使用新的辅助方法生成类型提示和默认值
315            let type_hint = self.type_info_to_hint(&property_schema.type_info);
316            let default_value = if let Some(default) = &property_schema.default {
317                self.value_to_string(default)
318            } else {
319                self.type_info_to_default(&property_schema.type_info)
320            };
321
322            // 构建插入文本:key = value  # type
323            let insert_text = format!("{} = {}  # {}", key, default_value, type_hint);
324
325            // 构建文档
326            let mut doc_parts = Vec::new();
327
328            if !property_schema.description.is_empty() {
329                doc_parts.push(property_schema.description.clone());
330            }
331
332            doc_parts.push(format!("**类型**: `{}`", type_hint));
333
334            if let Some(default) = &property_schema.default {
335                doc_parts.push(format!("**默认值**: `{}`", self.value_to_string(default)));
336            }
337
338            if property_schema.required {
339                doc_parts.push("**必需**: 是".to_string());
340            }
341
342            if let Some(deprecated_msg) = &property_schema.deprecated {
343                doc_parts.push(format!("**已废弃**: {}", deprecated_msg));
344            }
345
346            let documentation = Documentation::MarkupContent(MarkupContent {
347                kind: MarkupKind::Markdown,
348                value: doc_parts.join("\n\n"),
349            });
350
351            completions.push(CompletionItem {
352                label: key.clone(),
353                kind: Some(CompletionItemKind::PROPERTY),
354                detail: Some(format!("{}: {}", key, type_hint)),
355                documentation: Some(documentation),
356                insert_text: Some(insert_text),
357                insert_text_format: Some(lsp_types::InsertTextFormat::PLAIN_TEXT),
358                deprecated: property_schema.deprecated.is_some().then_some(true),
359                ..Default::default()
360            });
361        }
362
363        completions
364    }
365
366    /// 将 JSON 值转换为 TOML 字符串
367    #[allow(dead_code)]
368    fn json_value_to_toml_string(&self, value: &serde_json::Value) -> String {
369        match value {
370            serde_json::Value::String(s) => format!("\"{}\"", s),
371            serde_json::Value::Number(n) => n.to_string(),
372            serde_json::Value::Bool(b) => b.to_string(),
373            serde_json::Value::Array(_) => "[]".to_string(),
374            serde_json::Value::Object(_) => "{}".to_string(),
375            serde_json::Value::Null => "null".to_string(),
376        }
377    }
378
379    /// 根据类型名称返回默认值
380    #[allow(dead_code)]
381    fn type_to_default_value(&self, type_name: &str) -> String {
382        match type_name {
383            "string" => "\"\"".to_string(),
384            "integer" | "number" => "0".to_string(),
385            "boolean" => "false".to_string(),
386            "array" => "[]".to_string(),
387            "object" => "{}".to_string(),
388            _ => "\"\"".to_string(),
389        }
390    }
391
392    /// 补全枚举值
393    ///
394    /// 为具有枚举类型的配置项提供值补全
395    fn complete_enum_values(&self, values: &[String]) -> Vec<CompletionItem> {
396        values
397            .iter()
398            .map(|value| CompletionItem {
399                label: value.clone(),
400                kind: Some(CompletionItemKind::ENUM_MEMBER),
401                detail: Some(format!("枚举值: {}", value)),
402                documentation: Some(Documentation::MarkupContent(MarkupContent {
403                    kind: MarkupKind::Markdown,
404                    value: format!("枚举值 `{}`", value),
405                })),
406                insert_text: Some(format!("\"{}\"", value)),
407                insert_text_format: Some(lsp_types::InsertTextFormat::PLAIN_TEXT),
408                ..Default::default()
409            })
410            .collect()
411    }
412
413    /// 补全环境变量
414    ///
415    /// 提供常见的环境变量名称补全
416    pub fn complete_env_var(&self) -> Vec<CompletionItem> {
417        let common_vars = vec![
418            ("HOST", "主机地址"),
419            ("PORT", "端口号"),
420            ("DATABASE_URL", "数据库连接 URL"),
421            ("REDIS_URL", "Redis 连接 URL"),
422            ("LOG_LEVEL", "日志级别"),
423            ("ENV", "运行环境"),
424            ("DEBUG", "调试模式"),
425        ];
426
427        common_vars
428            .into_iter()
429            .map(|(name, description)| CompletionItem {
430                label: name.to_string(),
431                kind: Some(CompletionItemKind::VARIABLE),
432                detail: Some(description.to_string()),
433                documentation: Some(Documentation::MarkupContent(MarkupContent {
434                    kind: MarkupKind::Markdown,
435                    value: format!(
436                        "**{}**\n\n{}\n\n\
437                         **使用方式**:\n\
438                         ```toml\n\
439                         value = \"${{{}:default}}\"\n\
440                         ```",
441                        name, description, name
442                    ),
443                })),
444                insert_text: Some(format!("{}:${{1:default}}}}", name)),
445                insert_text_format: Some(lsp_types::InsertTextFormat::SNIPPET),
446                ..Default::default()
447            })
448            .collect()
449    }
450
451    /// 将类型信息转换为类型提示字符串
452    fn type_info_to_hint(&self, type_info: &crate::schema::TypeInfo) -> String {
453        match type_info {
454            crate::schema::TypeInfo::String {
455                enum_values: Some(values),
456                ..
457            } => {
458                format!("enum: {:?}", values)
459            }
460            crate::schema::TypeInfo::String { .. } => "string".to_string(),
461            crate::schema::TypeInfo::Integer { min, max } => {
462                if let (Some(min), Some(max)) = (min, max) {
463                    format!("integer ({} - {})", min, max)
464                } else {
465                    "integer".to_string()
466                }
467            }
468            crate::schema::TypeInfo::Float { .. } => "float".to_string(),
469            crate::schema::TypeInfo::Boolean => "boolean".to_string(),
470            crate::schema::TypeInfo::Array { .. } => "array".to_string(),
471            crate::schema::TypeInfo::Object { .. } => "object".to_string(),
472        }
473    }
474
475    /// 将类型信息转换为默认值字符串
476    fn type_info_to_default(&self, type_info: &crate::schema::TypeInfo) -> String {
477        match type_info {
478            crate::schema::TypeInfo::String {
479                enum_values: Some(values),
480                ..
481            } => {
482                if let Some(first) = values.first() {
483                    format!("\"{}\"", first)
484                } else {
485                    "\"\"".to_string()
486                }
487            }
488            crate::schema::TypeInfo::String { .. } => "\"\"".to_string(),
489            crate::schema::TypeInfo::Integer { .. } => "0".to_string(),
490            crate::schema::TypeInfo::Float { .. } => "0.0".to_string(),
491            crate::schema::TypeInfo::Boolean => "false".to_string(),
492            crate::schema::TypeInfo::Array { .. } => "[]".to_string(),
493            crate::schema::TypeInfo::Object { .. } => "{}".to_string(),
494        }
495    }
496
497    /// 将 Schema 值转换为字符串
498    fn value_to_string(&self, value: &crate::schema::Value) -> String {
499        match value {
500            crate::schema::Value::String(s) => format!("\"{}\"", s),
501            crate::schema::Value::Integer(i) => i.to_string(),
502            crate::schema::Value::Float(f) => f.to_string(),
503            crate::schema::Value::Boolean(b) => b.to_string(),
504            crate::schema::Value::Array(_) => "[]".to_string(),
505            crate::schema::Value::Table(_) => "{}".to_string(),
506        }
507    }
508
509    /// 为宏参数提供补全
510    ///
511    /// 根据宏的类型提供相应的参数补全项
512    ///
513    /// # Arguments
514    ///
515    /// * `macro_info` - 宏信息
516    /// * `cursor_position` - 光标位置(用于上下文感知补全)
517    ///
518    /// # Returns
519    ///
520    /// 返回补全项列表
521    pub fn complete_macro(
522        &self,
523        macro_info: &SummerMacro,
524        _cursor_position: Option<&str>,
525    ) -> Vec<CompletionItem> {
526        match macro_info {
527            SummerMacro::DeriveService(_) => self.complete_service_macro(),
528            SummerMacro::Component(_) => self.complete_component_macro(),
529            SummerMacro::Inject(_) => self.complete_inject_macro(),
530            SummerMacro::AutoConfig(_) => self.complete_auto_config_macro(),
531            SummerMacro::Route(_) => self.complete_route_macro(),
532            SummerMacro::Job(_) => self.complete_job_macro(),
533        }
534    }
535
536    /// 为 Component 宏提供补全
537    ///
538    /// 提供 name 参数的补全
539    fn complete_component_macro(&self) -> Vec<CompletionItem> {
540        vec![CompletionItem {
541            label: "name".to_string(),
542            kind: Some(CompletionItemKind::PROPERTY),
543            detail: Some("插件名称".to_string()),
544            documentation: Some(Documentation::String(
545                "指定自定义的插件名称,默认使用组件类型名 + \"Plugin\"".to_string(),
546            )),
547            insert_text: Some("name = \"$1\"".to_string()),
548            insert_text_format: Some(InsertTextFormat::SNIPPET),
549            ..Default::default()
550        }]
551    }
552
553    /// 为 Service 宏提供补全
554    ///
555    /// 提供 inject 属性的参数补全
556    fn complete_service_macro(&self) -> Vec<CompletionItem> {
557        vec![
558            // inject(component) 补全
559            CompletionItem {
560                label: "inject(component)".to_string(),
561                kind: Some(CompletionItemKind::PROPERTY),
562                detail: Some("注入组件".to_string()),
563                documentation: Some(Documentation::MarkupContent(MarkupContent {
564                    kind: MarkupKind::Markdown,
565                    value: "从应用上下文中注入已注册的组件实例。\n\n\
566                            **示例**:\n\
567                            ```rust\n\
568                            #[inject(component)]\n\
569                            db: ConnectPool,\n\
570                            ```"
571                        .to_string(),
572                })),
573                insert_text: Some("inject(component)".to_string()),
574                ..Default::default()
575            },
576            // inject(component = "name") 补全
577            CompletionItem {
578                label: "inject(component = \"name\")".to_string(),
579                kind: Some(CompletionItemKind::PROPERTY),
580                detail: Some("注入指定名称的组件".to_string()),
581                documentation: Some(Documentation::MarkupContent(MarkupContent {
582                    kind: MarkupKind::Markdown,
583                    value: "使用指定名称从应用上下文中注入组件,适用于多实例场景(如多数据源)。\n\n\
584                            **示例**:\n\
585                            ```rust\n\
586                            #[inject(component = \"primary\")]\n\
587                            primary_db: ConnectPool,\n\
588                            ```"
589                        .to_string(),
590                })),
591                insert_text: Some("inject(component = \"$1\")".to_string()),
592                insert_text_format: Some(lsp_types::InsertTextFormat::SNIPPET),
593                ..Default::default()
594            },
595            // inject(config) 补全
596            CompletionItem {
597                label: "inject(config)".to_string(),
598                kind: Some(CompletionItemKind::PROPERTY),
599                detail: Some("注入配置".to_string()),
600                documentation: Some(Documentation::MarkupContent(MarkupContent {
601                    kind: MarkupKind::Markdown,
602                    value: "从配置文件中加载配置项。配置项通过 `#[config_prefix]` 指定的前缀从 `config/app.toml` 中读取。\n\n\
603                            **示例**:\n\
604                            ```rust\n\
605                            #[inject(config)]\n\
606                            config: MyConfig,\n\
607                            ```"
608                        .to_string(),
609                })),
610                insert_text: Some("inject(config)".to_string()),
611                ..Default::default()
612            },
613        ]
614    }
615
616    /// 为 Inject 宏提供补全
617    ///
618    /// 提供注入类型的补全(component, config)
619    fn complete_inject_macro(&self) -> Vec<CompletionItem> {
620        vec![
621            // component 补全
622            CompletionItem {
623                label: "component".to_string(),
624                kind: Some(CompletionItemKind::KEYWORD),
625                detail: Some("注入组件".to_string()),
626                documentation: Some(Documentation::MarkupContent(MarkupContent {
627                    kind: MarkupKind::Markdown,
628                    value: "从应用上下文中注入已注册的组件实例。\n\n\
629                            **使用方式**:\n\
630                            - `#[inject(component)]` - 按类型自动查找\n\
631                            - `#[inject(component = \"name\")]` - 按名称查找"
632                        .to_string(),
633                })),
634                insert_text: Some("component".to_string()),
635                ..Default::default()
636            },
637            // config 补全
638            CompletionItem {
639                label: "config".to_string(),
640                kind: Some(CompletionItemKind::KEYWORD),
641                detail: Some("注入配置".to_string()),
642                documentation: Some(Documentation::MarkupContent(MarkupContent {
643                    kind: MarkupKind::Markdown,
644                    value: "从配置文件中加载配置项。\n\n\
645                            **使用方式**:\n\
646                            - `#[inject(config)]` - 从 config/app.toml 加载配置"
647                        .to_string(),
648                })),
649                insert_text: Some("config".to_string()),
650                ..Default::default()
651            },
652        ]
653    }
654
655    /// 为 AutoConfig 宏提供补全
656    ///
657    /// 提供常见的配置器类型补全
658    fn complete_auto_config_macro(&self) -> Vec<CompletionItem> {
659        vec![
660            CompletionItem {
661                label: "WebConfigurator".to_string(),
662                kind: Some(CompletionItemKind::CLASS),
663                detail: Some("Web 路由配置器".to_string()),
664                documentation: Some(Documentation::MarkupContent(MarkupContent {
665                    kind: MarkupKind::Markdown,
666                    value: "自动注册 Web 路由处理器。\n\n\
667                            **示例**:\n\
668                            ```rust\n\
669                            #[auto_config(WebConfigurator)]\n\
670                            #[tokio::main]\n\
671                            async fn main() {\n\
672                                App::new().add_plugin(WebPlugin).run().await\n\
673                            }\n\
674                            ```"
675                    .to_string(),
676                })),
677                insert_text: Some("WebConfigurator".to_string()),
678                ..Default::default()
679            },
680            CompletionItem {
681                label: "JobConfigurator".to_string(),
682                kind: Some(CompletionItemKind::CLASS),
683                detail: Some("任务调度配置器".to_string()),
684                documentation: Some(Documentation::MarkupContent(MarkupContent {
685                    kind: MarkupKind::Markdown,
686                    value: "自动注册定时任务。\n\n\
687                            **示例**:\n\
688                            ```rust\n\
689                            #[auto_config(JobConfigurator)]\n\
690                            #[tokio::main]\n\
691                            async fn main() {\n\
692                                App::new().add_plugin(JobPlugin).run().await\n\
693                            }\n\
694                            ```"
695                    .to_string(),
696                })),
697                insert_text: Some("JobConfigurator".to_string()),
698                ..Default::default()
699            },
700            CompletionItem {
701                label: "StreamConfigurator".to_string(),
702                kind: Some(CompletionItemKind::CLASS),
703                detail: Some("流处理配置器".to_string()),
704                documentation: Some(Documentation::MarkupContent(MarkupContent {
705                    kind: MarkupKind::Markdown,
706                    value: "自动注册流消费者。\n\n\
707                            **示例**:\n\
708                            ```rust\n\
709                            #[auto_config(StreamConfigurator)]\n\
710                            #[tokio::main]\n\
711                            async fn main() {\n\
712                                App::new().add_plugin(StreamPlugin).run().await\n\
713                            }\n\
714                            ```"
715                    .to_string(),
716                })),
717                insert_text: Some("StreamConfigurator".to_string()),
718                ..Default::default()
719            },
720        ]
721    }
722
723    /// 为路由宏提供补全
724    ///
725    /// 提供 HTTP 方法和路径参数的补全
726    fn complete_route_macro(&self) -> Vec<CompletionItem> {
727        let mut completions = Vec::new();
728
729        // HTTP 方法补全
730        let methods = vec![
731            ("GET", "获取资源"),
732            ("POST", "创建资源"),
733            ("PUT", "更新资源(完整)"),
734            ("DELETE", "删除资源"),
735            ("PATCH", "更新资源(部分)"),
736            ("HEAD", "获取资源头信息"),
737            ("OPTIONS", "获取支持的方法"),
738        ];
739
740        for (method, description) in methods {
741            completions.push(CompletionItem {
742                label: method.to_string(),
743                kind: Some(CompletionItemKind::CONSTANT),
744                detail: Some(description.to_string()),
745                documentation: Some(Documentation::MarkupContent(MarkupContent {
746                    kind: MarkupKind::Markdown,
747                    value: format!(
748                        "HTTP {} 方法\n\n\
749                         **示例**:\n\
750                         ```rust\n\
751                         #[{}(\"/path\")]\n\
752                         async fn handler() -> impl IntoResponse {{\n\
753                         }}\n\
754                         ```",
755                        method,
756                        method.to_lowercase()
757                    ),
758                })),
759                insert_text: Some(method.to_string()),
760                ..Default::default()
761            });
762        }
763
764        // 路径参数模板补全
765        completions.push(CompletionItem {
766            label: "{id}".to_string(),
767            kind: Some(CompletionItemKind::SNIPPET),
768            detail: Some("路径参数".to_string()),
769            documentation: Some(Documentation::MarkupContent(MarkupContent {
770                kind: MarkupKind::Markdown,
771                value: "路径参数占位符,用于捕获 URL 中的动态部分。\n\n\
772                        **示例**:\n\
773                        ```rust\n\
774                        #[get(\"/users/{id}\")]\n\
775                        async fn get_user(Path(id): Path<i64>) -> impl IntoResponse {\n\
776                        }\n\
777                        ```"
778                .to_string(),
779            })),
780            insert_text: Some("{${1:id}}".to_string()),
781            insert_text_format: Some(lsp_types::InsertTextFormat::SNIPPET),
782            ..Default::default()
783        });
784
785        completions
786    }
787
788    /// 为任务调度宏提供补全
789    ///
790    /// 提供 cron 表达式、延迟和频率值的补全
791    fn complete_job_macro(&self) -> Vec<CompletionItem> {
792        vec![
793            // Cron 表达式示例
794            CompletionItem {
795                label: "0 0 * * * *".to_string(),
796                kind: Some(CompletionItemKind::SNIPPET),
797                detail: Some("每小时执行".to_string()),
798                documentation: Some(Documentation::MarkupContent(MarkupContent {
799                    kind: MarkupKind::Markdown,
800                    value: "Cron 表达式:每小时的第 0 分 0 秒执行\n\n\
801                            **格式**: 秒 分 时 日 月 星期\n\n\
802                            **示例**:\n\
803                            ```rust\n\
804                            #[cron(\"0 0 * * * *\")]\n\
805                            async fn hourly_job() {\n\
806                            }\n\
807                            ```"
808                    .to_string(),
809                })),
810                insert_text: Some("\"0 0 * * * *\"".to_string()),
811                ..Default::default()
812            },
813            CompletionItem {
814                label: "0 0 0 * * *".to_string(),
815                kind: Some(CompletionItemKind::SNIPPET),
816                detail: Some("每天午夜执行".to_string()),
817                documentation: Some(Documentation::MarkupContent(MarkupContent {
818                    kind: MarkupKind::Markdown,
819                    value: "Cron 表达式:每天午夜 00:00:00 执行\n\n\
820                            **格式**: 秒 分 时 日 月 星期\n\n\
821                            **示例**:\n\
822                            ```rust\n\
823                            #[cron(\"0 0 0 * * *\")]\n\
824                            async fn daily_job() {\n\
825                            }\n\
826                            ```"
827                    .to_string(),
828                })),
829                insert_text: Some("\"0 0 0 * * *\"".to_string()),
830                ..Default::default()
831            },
832            CompletionItem {
833                label: "0 */5 * * * *".to_string(),
834                kind: Some(CompletionItemKind::SNIPPET),
835                detail: Some("每 5 分钟执行".to_string()),
836                documentation: Some(Documentation::MarkupContent(MarkupContent {
837                    kind: MarkupKind::Markdown,
838                    value: "Cron 表达式:每 5 分钟执行一次\n\n\
839                            **格式**: 秒 分 时 日 月 星期\n\n\
840                            **示例**:\n\
841                            ```rust\n\
842                            #[cron(\"0 */5 * * * *\")]\n\
843                            async fn every_five_minutes() {\n\
844                            }\n\
845                            ```"
846                    .to_string(),
847                })),
848                insert_text: Some("\"0 */5 * * * *\"".to_string()),
849                ..Default::default()
850            },
851            // fix_delay 值示例
852            CompletionItem {
853                label: "5".to_string(),
854                kind: Some(CompletionItemKind::VALUE),
855                detail: Some("延迟 5 秒".to_string()),
856                documentation: Some(Documentation::MarkupContent(MarkupContent {
857                    kind: MarkupKind::Markdown,
858                    value: "任务完成后延迟 5 秒再次执行\n\n\
859                            **示例**:\n\
860                            ```rust\n\
861                            #[fix_delay(5)]\n\
862                            async fn delayed_job() {\n\
863                            }\n\
864                            ```"
865                    .to_string(),
866                })),
867                insert_text: Some("5".to_string()),
868                ..Default::default()
869            },
870            CompletionItem {
871                label: "10".to_string(),
872                kind: Some(CompletionItemKind::VALUE),
873                detail: Some("延迟/频率 10 秒".to_string()),
874                documentation: Some(Documentation::MarkupContent(MarkupContent {
875                    kind: MarkupKind::Markdown,
876                    value: "延迟或频率为 10 秒\n\n\
877                            **fix_delay 示例**:\n\
878                            ```rust\n\
879                            #[fix_delay(10)]\n\
880                            async fn delayed_job() {\n\
881                            }\n\
882                            ```\n\n\
883                            **fix_rate 示例**:\n\
884                            ```rust\n\
885                            #[fix_rate(10)]\n\
886                            async fn periodic_job() {\n\
887                            }\n\
888                            ```"
889                    .to_string(),
890                })),
891                insert_text: Some("10".to_string()),
892                ..Default::default()
893            },
894            CompletionItem {
895                label: "60".to_string(),
896                kind: Some(CompletionItemKind::VALUE),
897                detail: Some("延迟/频率 60 秒(1 分钟)".to_string()),
898                documentation: Some(Documentation::MarkupContent(MarkupContent {
899                    kind: MarkupKind::Markdown,
900                    value: "延迟或频率为 60 秒(1 分钟)\n\n\
901                            **fix_delay 示例**:\n\
902                            ```rust\n\
903                            #[fix_delay(60)]\n\
904                            async fn delayed_job() {\n\
905                            }\n\
906                            ```\n\n\
907                            **fix_rate 示例**:\n\
908                            ```rust\n\
909                            #[fix_rate(60)]\n\
910                            async fn periodic_job() {\n\
911                            }\n\
912                            ```"
913                    .to_string(),
914                })),
915                insert_text: Some("60".to_string()),
916                ..Default::default()
917            },
918        ]
919    }
920}
921
922impl Default for CompletionEngine {
923    fn default() -> Self {
924        Self::new(SchemaProvider::default())
925    }
926}
927
928#[cfg(test)]
929mod tests;