1use crate::types::*;
11use async_trait::async_trait;
12use tree_sitter::{Language, Parser};
13
14#[async_trait]
36pub trait ContextAnalyzer: Send + Sync {
37 async fn analyze_context(
56 &self,
57 code: &str,
58 position: Position,
59 language: &str,
60 ) -> CompletionResult<CompletionContext>;
61
62 fn get_available_symbols(&self, context: &CompletionContext, code: &str) -> Vec<Symbol>;
73
74 fn infer_expected_type(&self, context: &CompletionContext) -> Option<Type>;
84}
85
86pub struct TreeSitterContextAnalyzer;
111
112impl TreeSitterContextAnalyzer {
113 fn get_language(language: &str) -> Option<Language> {
115 match language {
116 "rust" => Some(tree_sitter_rust::language()),
117 "typescript" | "ts" | "tsx" | "javascript" | "js" | "jsx" => {
118 Some(tree_sitter_typescript::language_typescript())
119 }
120 "python" | "py" => Some(tree_sitter_python::language()),
121 _ => None,
122 }
123 }
124
125 fn get_builtin_symbols(language: &str) -> Vec<Symbol> {
127 match language {
128 "rust" => vec![
129 Symbol {
130 name: "String".to_string(),
131 kind: SymbolKind::Type,
132 scope: Scope {
133 kind: ScopeKind::Global,
134 name: None,
135 range: Range::new(Position::new(0, 0), Position::new(0, 0)),
136 },
137 type_info: Some("std::string::String".to_string()),
138 documentation: Some("A UTF-8 encoded string".to_string()),
139 },
140 Symbol {
141 name: "Vec".to_string(),
142 kind: SymbolKind::Type,
143 scope: Scope {
144 kind: ScopeKind::Global,
145 name: None,
146 range: Range::new(Position::new(0, 0), Position::new(0, 0)),
147 },
148 type_info: Some("std::vec::Vec".to_string()),
149 documentation: Some("A growable array".to_string()),
150 },
151 Symbol {
152 name: "Option".to_string(),
153 kind: SymbolKind::Type,
154 scope: Scope {
155 kind: ScopeKind::Global,
156 name: None,
157 range: Range::new(Position::new(0, 0), Position::new(0, 0)),
158 },
159 type_info: Some("std::option::Option".to_string()),
160 documentation: Some("An optional value".to_string()),
161 },
162 Symbol {
163 name: "Result".to_string(),
164 kind: SymbolKind::Type,
165 scope: Scope {
166 kind: ScopeKind::Global,
167 name: None,
168 range: Range::new(Position::new(0, 0), Position::new(0, 0)),
169 },
170 type_info: Some("std::result::Result".to_string()),
171 documentation: Some("A result type for error handling".to_string()),
172 },
173 ],
174 "typescript" | "javascript" => vec![
175 Symbol {
176 name: "Array".to_string(),
177 kind: SymbolKind::Type,
178 scope: Scope {
179 kind: ScopeKind::Global,
180 name: None,
181 range: Range::new(Position::new(0, 0), Position::new(0, 0)),
182 },
183 type_info: Some("Array".to_string()),
184 documentation: Some("A JavaScript array".to_string()),
185 },
186 Symbol {
187 name: "Object".to_string(),
188 kind: SymbolKind::Type,
189 scope: Scope {
190 kind: ScopeKind::Global,
191 name: None,
192 range: Range::new(Position::new(0, 0), Position::new(0, 0)),
193 },
194 type_info: Some("Object".to_string()),
195 documentation: Some("A JavaScript object".to_string()),
196 },
197 Symbol {
198 name: "Promise".to_string(),
199 kind: SymbolKind::Type,
200 scope: Scope {
201 kind: ScopeKind::Global,
202 name: None,
203 range: Range::new(Position::new(0, 0), Position::new(0, 0)),
204 },
205 type_info: Some("Promise".to_string()),
206 documentation: Some("A promise for async operations".to_string()),
207 },
208 Symbol {
209 name: "Map".to_string(),
210 kind: SymbolKind::Type,
211 scope: Scope {
212 kind: ScopeKind::Global,
213 name: None,
214 range: Range::new(Position::new(0, 0), Position::new(0, 0)),
215 },
216 type_info: Some("Map".to_string()),
217 documentation: Some("A key-value map".to_string()),
218 },
219 ],
220 "python" => vec![
221 Symbol {
222 name: "list".to_string(),
223 kind: SymbolKind::Type,
224 scope: Scope {
225 kind: ScopeKind::Global,
226 name: None,
227 range: Range::new(Position::new(0, 0), Position::new(0, 0)),
228 },
229 type_info: Some("list".to_string()),
230 documentation: Some("A Python list".to_string()),
231 },
232 Symbol {
233 name: "dict".to_string(),
234 kind: SymbolKind::Type,
235 scope: Scope {
236 kind: ScopeKind::Global,
237 name: None,
238 range: Range::new(Position::new(0, 0), Position::new(0, 0)),
239 },
240 type_info: Some("dict".to_string()),
241 documentation: Some("A Python dictionary".to_string()),
242 },
243 Symbol {
244 name: "str".to_string(),
245 kind: SymbolKind::Type,
246 scope: Scope {
247 kind: ScopeKind::Global,
248 name: None,
249 range: Range::new(Position::new(0, 0), Position::new(0, 0)),
250 },
251 type_info: Some("str".to_string()),
252 documentation: Some("A Python string".to_string()),
253 },
254 Symbol {
255 name: "int".to_string(),
256 kind: SymbolKind::Type,
257 scope: Scope {
258 kind: ScopeKind::Global,
259 name: None,
260 range: Range::new(Position::new(0, 0), Position::new(0, 0)),
261 },
262 type_info: Some("int".to_string()),
263 documentation: Some("A Python integer".to_string()),
264 },
265 ],
266 _ => Vec::new(),
267 }
268 }
269
270 fn collect_imported_symbols(code: &str, language: &str) -> Vec<Symbol> {
272 let mut symbols = Vec::new();
273
274 match language {
275 "rust" => {
276 for line in code.lines() {
278 if line.trim().starts_with("use ") {
279 if let Some(imported) = Self::extract_rust_import(line) {
281 symbols.push(Symbol {
282 name: imported.clone(),
283 kind: SymbolKind::Module,
284 scope: Scope {
285 kind: ScopeKind::Global,
286 name: None,
287 range: Range::new(Position::new(0, 0), Position::new(0, 0)),
288 },
289 type_info: None,
290 documentation: None,
291 });
292 }
293 }
294 }
295 }
296 "typescript" | "javascript" => {
297 for line in code.lines() {
299 if line.trim().starts_with("import ") {
300 if let Some(imported) = Self::extract_typescript_import(line) {
302 symbols.push(Symbol {
303 name: imported.clone(),
304 kind: SymbolKind::Module,
305 scope: Scope {
306 kind: ScopeKind::Global,
307 name: None,
308 range: Range::new(Position::new(0, 0), Position::new(0, 0)),
309 },
310 type_info: None,
311 documentation: None,
312 });
313 }
314 }
315 }
316 }
317 "python" => {
318 for line in code.lines() {
320 if line.trim().starts_with("import ") || line.trim().starts_with("from ") {
321 if let Some(imported) = Self::extract_python_import(line) {
323 symbols.push(Symbol {
324 name: imported.clone(),
325 kind: SymbolKind::Module,
326 scope: Scope {
327 kind: ScopeKind::Global,
328 name: None,
329 range: Range::new(Position::new(0, 0), Position::new(0, 0)),
330 },
331 type_info: None,
332 documentation: None,
333 });
334 }
335 }
336 }
337 }
338 _ => {}
339 }
340
341 symbols
342 }
343
344 fn extract_rust_import(line: &str) -> Option<String> {
346 let line = line.trim();
347 let import_part = line.strip_prefix("use ")?;
348 let import_part = import_part.trim_end_matches(';');
349
350 if let Some(last_colon) = import_part.rfind("::") {
352 let name = &import_part[last_colon + 2..];
353 if !name.is_empty() && !name.contains('{') {
354 return Some(name.to_string());
355 }
356 }
357
358 if import_part.ends_with("::*") {
360 return Some("*".to_string());
361 }
362
363 if !import_part.contains("::") && !import_part.contains('{') {
365 return Some(import_part.to_string());
366 }
367
368 None
369 }
370
371 fn extract_typescript_import(line: &str) -> Option<String> {
373 let line = line.trim();
374 let line = line.strip_prefix("import ")?;
375
376 if let Some(start) = line.find('{') {
378 if let Some(end) = line.find('}') {
379 let names = &line[start + 1..end];
380 if let Some(name) = names.split(',').next() {
382 return Some(name.trim().to_string());
383 }
384 }
385 }
386
387 if let Some(from_pos) = line.find(" from ") {
389 let import_part = &line[..from_pos];
390 return Some(import_part.trim().to_string());
391 }
392
393 None
394 }
395
396 fn extract_python_import(line: &str) -> Option<String> {
398 let line = line.trim();
399
400 if let Some(import_part) = line.strip_prefix("import ") {
401 if let Some(as_pos) = import_part.find(" as ") {
403 return Some(import_part[as_pos + 4..].trim().to_string());
404 }
405 return Some(import_part.split(',').next()?.trim().to_string());
406 }
407
408 if let Some(rest) = line.strip_prefix("from ") {
409 if let Some(import_pos) = rest.find(" import ") {
411 let import_part = &rest[import_pos + 8..];
412 if let Some(name) = import_part.split(',').next() {
414 return Some(name.trim().to_string());
415 }
416 }
417 }
418
419 None
420 }
421
422 fn collect_scope_symbols_with_code(context: &CompletionContext, code: &str) -> Vec<Symbol> {
424 let mut symbols = Vec::new();
425
426 match context.language.as_str() {
427 "rust" => {
428 symbols.extend(Self::collect_rust_scope_symbols(code, context));
429 }
430 "typescript" | "javascript" => {
431 symbols.extend(Self::collect_typescript_scope_symbols(code, context));
432 }
433 "python" => {
434 symbols.extend(Self::collect_python_scope_symbols(code, context));
435 }
436 _ => {}
437 }
438
439 symbols
440 }
441
442 fn collect_rust_scope_symbols(code: &str, context: &CompletionContext) -> Vec<Symbol> {
444 let mut symbols = Vec::new();
445 let byte_offset = Self::position_to_byte_offset(code, context.position);
446 let code_before = &code[..byte_offset];
447
448 for line in code_before.lines().rev() {
450 let trimmed = line.trim();
451
452 if trimmed.starts_with("let ") || trimmed.starts_with("let mut ") {
454 if let Some(name) = Self::extract_rust_variable_name(trimmed) {
455 symbols.push(Symbol {
456 name: name.clone(),
457 kind: SymbolKind::Variable,
458 scope: context.scope.clone(),
459 type_info: None,
460 documentation: None,
461 });
462 }
463 }
464
465 if trimmed.starts_with("const ") {
467 if let Some(name) = Self::extract_rust_variable_name(trimmed) {
468 symbols.push(Symbol {
469 name: name.clone(),
470 kind: SymbolKind::Constant,
471 scope: context.scope.clone(),
472 type_info: None,
473 documentation: None,
474 });
475 }
476 }
477
478 if context.scope.kind == ScopeKind::Function && trimmed.starts_with("fn ") {
480 if let Some(params) = Self::extract_rust_function_params(trimmed) {
481 for param in params {
482 symbols.push(Symbol {
483 name: param.clone(),
484 kind: SymbolKind::Parameter,
485 scope: context.scope.clone(),
486 type_info: None,
487 documentation: None,
488 });
489 }
490 }
491 break; }
493 }
494
495 symbols
496 }
497
498 fn extract_rust_variable_name(line: &str) -> Option<String> {
500 let line = if let Some(stripped) = line.strip_prefix("let mut ") {
501 stripped
502 } else if let Some(stripped) = line.strip_prefix("let ") {
503 stripped
504 } else if let Some(stripped) = line.strip_prefix("const ") {
505 stripped
506 } else {
507 return None;
508 };
509
510 let name = if let Some(colon_pos) = line.find(':') {
512 &line[..colon_pos]
513 } else if let Some(eq_pos) = line.find('=') {
514 &line[..eq_pos]
515 } else {
516 line
517 };
518
519 let name = name.trim();
520 if !name.is_empty() && name.chars().all(|c| c.is_alphanumeric() || c == '_') {
521 Some(name.to_string())
522 } else {
523 None
524 }
525 }
526
527 fn extract_rust_function_params(line: &str) -> Option<Vec<String>> {
529 if !line.starts_with("fn ") {
530 return None;
531 }
532
533 if let Some(start) = line.find('(') {
535 if let Some(end) = line.find(')') {
536 let params_str = &line[start + 1..end];
537 let mut params = Vec::new();
538
539 for param in params_str.split(',') {
540 let param = param.trim();
541 if !param.is_empty() {
542 if let Some(colon_pos) = param.find(':') {
544 let name = param[..colon_pos].trim();
545 if !name.is_empty() {
546 params.push(name.to_string());
547 }
548 }
549 }
550 }
551
552 return Some(params);
553 }
554 }
555
556 None
557 }
558
559 fn collect_typescript_scope_symbols(code: &str, context: &CompletionContext) -> Vec<Symbol> {
561 let mut symbols = Vec::new();
562 let byte_offset = Self::position_to_byte_offset(code, context.position);
563 let code_before = &code[..byte_offset];
564
565 for line in code_before.lines().rev() {
567 let trimmed = line.trim();
568
569 if trimmed.starts_with("let ")
571 || trimmed.starts_with("const ")
572 || trimmed.starts_with("var ")
573 {
574 if let Some(name) = Self::extract_typescript_variable_name(trimmed) {
575 let kind = if trimmed.starts_with("const ") {
576 SymbolKind::Constant
577 } else {
578 SymbolKind::Variable
579 };
580
581 symbols.push(Symbol {
582 name: name.clone(),
583 kind,
584 scope: context.scope.clone(),
585 type_info: None,
586 documentation: None,
587 });
588 }
589 }
590
591 if context.scope.kind == ScopeKind::Function
593 && (trimmed.starts_with("function ") || trimmed.contains("=>"))
594 {
595 if let Some(params) = Self::extract_typescript_function_params(trimmed) {
596 for param in params {
597 symbols.push(Symbol {
598 name: param.clone(),
599 kind: SymbolKind::Parameter,
600 scope: context.scope.clone(),
601 type_info: None,
602 documentation: None,
603 });
604 }
605 }
606 break; }
608 }
609
610 symbols
611 }
612
613 fn extract_typescript_variable_name(line: &str) -> Option<String> {
615 let line = if let Some(stripped) = line.strip_prefix("let ") {
616 stripped
617 } else if let Some(stripped) = line.strip_prefix("const ") {
618 stripped
619 } else if let Some(stripped) = line.strip_prefix("var ") {
620 stripped
621 } else {
622 return None;
623 };
624
625 let name = if let Some(colon_pos) = line.find(':') {
627 &line[..colon_pos]
628 } else if let Some(eq_pos) = line.find('=') {
629 &line[..eq_pos]
630 } else {
631 line
632 };
633
634 let name = name.trim();
635 if !name.is_empty()
636 && name
637 .chars()
638 .all(|c| c.is_alphanumeric() || c == '_' || c == '$')
639 {
640 Some(name.to_string())
641 } else {
642 None
643 }
644 }
645
646 fn extract_typescript_function_params(line: &str) -> Option<Vec<String>> {
648 if let Some(start) = line.find('(') {
650 if let Some(end) = line.find(')') {
651 let params_str = &line[start + 1..end];
652 let mut params = Vec::new();
653
654 for param in params_str.split(',') {
655 let param = param.trim();
656 if !param.is_empty() {
657 let name = if let Some(colon_pos) = param.find(':') {
659 ¶m[..colon_pos]
660 } else if let Some(eq_pos) = param.find('=') {
661 ¶m[..eq_pos]
662 } else {
663 param
664 };
665
666 let name = name.trim();
667 if !name.is_empty() {
668 params.push(name.to_string());
669 }
670 }
671 }
672
673 return Some(params);
674 }
675 }
676
677 None
678 }
679
680 fn collect_python_scope_symbols(code: &str, context: &CompletionContext) -> Vec<Symbol> {
682 let mut symbols = Vec::new();
683 let byte_offset = Self::position_to_byte_offset(code, context.position);
684 let code_before = &code[..byte_offset];
685
686 for line in code_before.lines().rev() {
688 let trimmed = line.trim();
689
690 if trimmed.is_empty() || trimmed.starts_with('#') {
692 continue;
693 }
694
695 if let Some(eq_pos) = trimmed.find('=') {
697 if eq_pos > 0 && eq_pos < trimmed.len() - 1 {
699 let before = &trimmed[..eq_pos];
700 let after = &trimmed[eq_pos + 1..eq_pos + 2];
701
702 if after != "="
703 && !before.ends_with('!')
704 && !before.ends_with('<')
705 && !before.ends_with('>')
706 {
707 if let Some(name) = Self::extract_python_variable_name(before) {
708 symbols.push(Symbol {
709 name: name.clone(),
710 kind: SymbolKind::Variable,
711 scope: context.scope.clone(),
712 type_info: None,
713 documentation: None,
714 });
715 }
716 }
717 }
718 }
719
720 if context.scope.kind == ScopeKind::Function && trimmed.starts_with("def ") {
722 if let Some(params) = Self::extract_python_function_params(trimmed) {
723 for param in params {
724 symbols.push(Symbol {
725 name: param.clone(),
726 kind: SymbolKind::Parameter,
727 scope: context.scope.clone(),
728 type_info: None,
729 documentation: None,
730 });
731 }
732 }
733 break; }
735 }
736
737 symbols
738 }
739
740 fn extract_python_variable_name(line: &str) -> Option<String> {
742 let name = line.trim();
743 if !name.is_empty() && name.chars().all(|c| c.is_alphanumeric() || c == '_') {
744 Some(name.to_string())
745 } else {
746 None
747 }
748 }
749
750 fn extract_python_function_params(line: &str) -> Option<Vec<String>> {
752 if !line.starts_with("def ") {
753 return None;
754 }
755
756 if let Some(start) = line.find('(') {
758 if let Some(end) = line.find(')') {
759 let params_str = &line[start + 1..end];
760 let mut params = Vec::new();
761
762 for param in params_str.split(',') {
763 let param = param.trim();
764 if !param.is_empty() && param != "self" {
765 let name = if let Some(colon_pos) = param.find(':') {
767 ¶m[..colon_pos]
768 } else if let Some(eq_pos) = param.find('=') {
769 ¶m[..eq_pos]
770 } else {
771 param
772 };
773
774 let name = name.trim();
775 if !name.is_empty() {
776 params.push(name.to_string());
777 }
778 }
779 }
780
781 return Some(params);
782 }
783 }
784
785 None
786 }
787
788 fn parse_code(code: &str, language: &str) -> CompletionResult<tree_sitter::Tree> {
790 let lang = Self::get_language(language).ok_or_else(|| {
791 CompletionError::UnsupportedLanguage(format!(
792 "Language {} not supported by tree-sitter",
793 language
794 ))
795 })?;
796
797 let mut parser = Parser::new();
798 parser.set_language(lang).map_err(|_| {
799 CompletionError::ContextAnalysisError("Failed to set parser language".to_string())
800 })?;
801
802 parser.parse(code, None).ok_or_else(|| {
803 CompletionError::ContextAnalysisError("Failed to parse code".to_string())
804 })
805 }
806
807 fn detect_scope(
809 code: &str,
810 position: Position,
811 tree: &tree_sitter::Tree,
812 language: &str,
813 ) -> Scope {
814 let byte_offset = Self::position_to_byte_offset(code, position);
815 let root = tree.root_node();
816
817 let mut current_node = root;
819 let mut cursor = root.walk();
820
821 loop {
823 let mut found_child = false;
824 for child in current_node.children(&mut cursor) {
825 if child.start_byte() <= byte_offset && byte_offset <= child.end_byte() {
826 current_node = child;
827 found_child = true;
828 break;
829 }
830 }
831 if !found_child {
832 break;
833 }
834 }
835
836 let mut scope_kind = ScopeKind::Global;
838 let mut scope_name = None;
839
840 let mut node = current_node;
841 loop {
842 let node_type = node.kind();
843
844 match language {
845 "rust" => match node_type {
846 "function_item" => {
847 scope_kind = ScopeKind::Function;
848 scope_name = Self::extract_name_rust(node, code);
849 break;
850 }
851 "struct_item" => {
852 scope_kind = ScopeKind::Struct;
853 scope_name = Self::extract_name_rust(node, code);
854 break;
855 }
856 "impl_item" => {
857 scope_kind = ScopeKind::Impl;
858 scope_name = Self::extract_name_rust(node, code);
859 break;
860 }
861 "mod_item" => {
862 scope_kind = ScopeKind::Module;
863 scope_name = Self::extract_name_rust(node, code);
864 break;
865 }
866 "block" => {
867 scope_kind = ScopeKind::Block;
868 }
869 _ => {}
870 },
871 "typescript" | "javascript" => match node_type {
872 "function_declaration" | "function" => {
873 scope_kind = ScopeKind::Function;
874 scope_name = Self::extract_name_typescript(node, code);
875 break;
876 }
877 "class_declaration" => {
878 scope_kind = ScopeKind::Class;
879 scope_name = Self::extract_name_typescript(node, code);
880 break;
881 }
882 "method_definition" => {
883 scope_kind = ScopeKind::Function;
884 scope_name = Self::extract_name_typescript(node, code);
885 break;
886 }
887 "block" => {
888 scope_kind = ScopeKind::Block;
889 }
890 _ => {}
891 },
892 "python" => match node_type {
893 "function_definition" => {
894 scope_kind = ScopeKind::Function;
895 scope_name = Self::extract_name_python(node, code);
896 break;
897 }
898 "class_definition" => {
899 scope_kind = ScopeKind::Class;
900 scope_name = Self::extract_name_python(node, code);
901 break;
902 }
903 "block" => {
904 scope_kind = ScopeKind::Block;
905 }
906 _ => {}
907 },
908 _ => {}
909 }
910
911 if let Some(parent) = node.parent() {
912 node = parent;
913 } else {
914 break;
915 }
916 }
917
918 Scope {
919 kind: scope_kind,
920 name: scope_name,
921 range: Range::new(
922 Self::byte_offset_to_position(code, current_node.start_byte()),
923 Self::byte_offset_to_position(code, current_node.end_byte()),
924 ),
925 }
926 }
927
928 fn extract_name_rust(node: tree_sitter::Node, code: &str) -> Option<String> {
930 let mut cursor = node.walk();
931 for child in node.children(&mut cursor) {
932 if child.kind() == "identifier" {
933 if let Ok(text) = child.utf8_text(code.as_bytes()) {
934 return Some(text.to_string());
935 }
936 }
937 }
938 None
939 }
940
941 fn extract_name_typescript(node: tree_sitter::Node, code: &str) -> Option<String> {
943 let mut cursor = node.walk();
944 for child in node.children(&mut cursor) {
945 if child.kind() == "identifier" {
946 if let Ok(text) = child.utf8_text(code.as_bytes()) {
947 return Some(text.to_string());
948 }
949 }
950 }
951 None
952 }
953
954 fn extract_name_python(node: tree_sitter::Node, code: &str) -> Option<String> {
956 let mut cursor = node.walk();
957 for child in node.children(&mut cursor) {
958 if child.kind() == "identifier" {
959 if let Ok(text) = child.utf8_text(code.as_bytes()) {
960 return Some(text.to_string());
961 }
962 }
963 }
964 None
965 }
966
967 fn position_to_byte_offset(code: &str, position: Position) -> usize {
969 let mut byte_offset = 0;
970 let mut current_line = 0;
971 let mut current_char = 0;
972
973 for ch in code.chars() {
974 if current_line == position.line && current_char == position.character {
975 return byte_offset;
976 }
977
978 byte_offset += ch.len_utf8();
979
980 if ch == '\n' {
981 current_line += 1;
982 current_char = 0;
983 } else {
984 current_char += 1;
985 }
986 }
987
988 byte_offset
989 }
990
991 fn byte_offset_to_position(code: &str, byte_offset: usize) -> Position {
993 let mut current_line = 0;
994 let mut current_char = 0;
995 let mut current_byte = 0;
996
997 for ch in code.chars() {
998 if current_byte >= byte_offset {
999 return Position::new(current_line, current_char);
1000 }
1001
1002 current_byte += ch.len_utf8();
1003
1004 if ch == '\n' {
1005 current_line += 1;
1006 current_char = 0;
1007 } else {
1008 current_char += 1;
1009 }
1010 }
1011
1012 Position::new(current_line, current_char)
1013 }
1014
1015 fn extract_prefix(code: &str, position: Position) -> String {
1017 let byte_offset = Self::position_to_byte_offset(code, position);
1018 let mut prefix = String::new();
1019
1020 for ch in code[..byte_offset].chars().rev() {
1022 if ch.is_alphanumeric() || ch == '_' {
1023 prefix.insert(0, ch);
1024 } else {
1025 break;
1026 }
1027 }
1028
1029 prefix
1030 }
1031}
1032
1033#[async_trait]
1034impl ContextAnalyzer for TreeSitterContextAnalyzer {
1035 async fn analyze_context(
1036 &self,
1037 code: &str,
1038 position: Position,
1039 language: &str,
1040 ) -> CompletionResult<CompletionContext> {
1041 let tree = Self::parse_code(code, language)?;
1043
1044 let scope = Self::detect_scope(code, position, &tree, language);
1046
1047 let prefix = Self::extract_prefix(code, position);
1049
1050 let mut context = CompletionContext::new(language.to_string(), position, prefix);
1052 context.scope = scope;
1053
1054 context.available_symbols = self.get_available_symbols(&context, code);
1056
1057 context.expected_type = self.infer_expected_type(&context);
1059
1060 Ok(context)
1061 }
1062
1063 fn get_available_symbols(&self, context: &CompletionContext, code: &str) -> Vec<Symbol> {
1064 let mut symbols = Vec::new();
1066
1067 symbols.extend(Self::get_builtin_symbols(&context.language));
1069
1070 symbols.extend(Self::collect_imported_symbols(code, &context.language));
1072
1073 symbols.extend(Self::collect_scope_symbols_with_code(context, code));
1075
1076 symbols
1077 }
1078
1079 fn infer_expected_type(&self, context: &CompletionContext) -> Option<Type> {
1080 Self::infer_type_from_context(context)
1081 }
1082}
1083
1084impl TreeSitterContextAnalyzer {
1085 fn infer_type_from_context(context: &CompletionContext) -> Option<Type> {
1087 if let Some(type_info) = Self::infer_from_assignment(context) {
1089 return Some(type_info);
1090 }
1091
1092 if let Some(type_info) = Self::infer_from_function_param(context) {
1094 return Some(type_info);
1095 }
1096
1097 if let Some(type_info) = Self::infer_from_return_type(context) {
1099 return Some(type_info);
1100 }
1101
1102 None
1103 }
1104
1105 fn infer_from_assignment(context: &CompletionContext) -> Option<Type> {
1107 match context.language.as_str() {
1108 "rust" => Self::infer_rust_assignment_type(context),
1109 "typescript" | "javascript" => Self::infer_typescript_assignment_type(context),
1110 "python" => Self::infer_python_assignment_type(context),
1111 _ => None,
1112 }
1113 }
1114
1115 fn infer_rust_assignment_type(context: &CompletionContext) -> Option<Type> {
1117 if context.scope.kind == ScopeKind::Function || context.scope.kind == ScopeKind::Block {
1125 if context.prefix.contains("vec") || context.prefix.contains("Vec") {
1130 return Some(Type::new("Vec".to_string()).array());
1131 }
1132 if context.prefix.contains("string") || context.prefix.contains("String") {
1133 return Some(Type::new("String".to_string()));
1134 }
1135 if context.prefix.contains("option") || context.prefix.contains("Option") {
1136 return Some(Type::new("Option".to_string()).optional());
1137 }
1138 if context.prefix.contains("result") || context.prefix.contains("Result") {
1139 return Some(Type::new("Result".to_string()));
1140 }
1141 }
1142
1143 None
1144 }
1145
1146 fn infer_typescript_assignment_type(context: &CompletionContext) -> Option<Type> {
1148 if context.prefix.contains("array") || context.prefix.contains("Array") {
1152 return Some(Type::new("Array".to_string()).array());
1153 }
1154 if context.prefix.contains("string") || context.prefix.contains("String") {
1155 return Some(Type::new("string".to_string()));
1156 }
1157 if context.prefix.contains("number") || context.prefix.contains("Number") {
1158 return Some(Type::new("number".to_string()));
1159 }
1160 if context.prefix.contains("promise") || context.prefix.contains("Promise") {
1161 return Some(Type::new("Promise".to_string()));
1162 }
1163 if context.prefix.contains("map") || context.prefix.contains("Map") {
1164 return Some(Type::new("Map".to_string()));
1165 }
1166
1167 None
1168 }
1169
1170 fn infer_python_assignment_type(context: &CompletionContext) -> Option<Type> {
1172 if context.prefix.contains("list") || context.prefix.contains("List") {
1176 return Some(Type::new("list".to_string()).array());
1177 }
1178 if context.prefix.contains("dict") || context.prefix.contains("Dict") {
1179 return Some(Type::new("dict".to_string()));
1180 }
1181 if context.prefix.contains("str") || context.prefix.contains("String") {
1182 return Some(Type::new("str".to_string()));
1183 }
1184 if context.prefix.contains("int") || context.prefix.contains("Integer") {
1185 return Some(Type::new("int".to_string()));
1186 }
1187 if context.prefix.contains("tuple") || context.prefix.contains("Tuple") {
1188 return Some(Type::new("tuple".to_string()).array());
1189 }
1190
1191 None
1192 }
1193
1194 fn infer_from_function_param(context: &CompletionContext) -> Option<Type> {
1196 match context.language.as_str() {
1197 "rust" => Self::infer_rust_function_param_type(context),
1198 "typescript" | "javascript" => Self::infer_typescript_function_param_type(context),
1199 "python" => Self::infer_python_function_param_type(context),
1200 _ => None,
1201 }
1202 }
1203
1204 fn infer_rust_function_param_type(context: &CompletionContext) -> Option<Type> {
1206 if context.scope.kind == ScopeKind::Function {
1208 if context.prefix.contains("&str") {
1210 return Some(Type::new("&str".to_string()));
1211 }
1212 if context.prefix.contains("&mut") {
1213 return Some(Type::new("&mut".to_string()));
1214 }
1215 if context.prefix.contains("&") {
1216 return Some(Type::new("&".to_string()));
1217 }
1218 }
1219
1220 None
1221 }
1222
1223 fn infer_typescript_function_param_type(context: &CompletionContext) -> Option<Type> {
1225 if context.scope.kind == ScopeKind::Function {
1227 if context.prefix.contains("string") {
1229 return Some(Type::new("string".to_string()));
1230 }
1231 if context.prefix.contains("number") {
1232 return Some(Type::new("number".to_string()));
1233 }
1234 if context.prefix.contains("boolean") {
1235 return Some(Type::new("boolean".to_string()));
1236 }
1237 if context.prefix.contains("any") {
1238 return Some(Type::new("any".to_string()));
1239 }
1240 }
1241
1242 None
1243 }
1244
1245 fn infer_python_function_param_type(context: &CompletionContext) -> Option<Type> {
1247 if context.scope.kind == ScopeKind::Function {
1249 if context.prefix.contains("str") {
1251 return Some(Type::new("str".to_string()));
1252 }
1253 if context.prefix.contains("int") {
1254 return Some(Type::new("int".to_string()));
1255 }
1256 if context.prefix.contains("float") {
1257 return Some(Type::new("float".to_string()));
1258 }
1259 if context.prefix.contains("bool") {
1260 return Some(Type::new("bool".to_string()));
1261 }
1262 }
1263
1264 None
1265 }
1266
1267 fn infer_from_return_type(context: &CompletionContext) -> Option<Type> {
1269 match context.language.as_str() {
1270 "rust" => Self::infer_rust_return_type(context),
1271 "typescript" | "javascript" => Self::infer_typescript_return_type(context),
1272 "python" => Self::infer_python_return_type(context),
1273 _ => None,
1274 }
1275 }
1276
1277 fn infer_rust_return_type(context: &CompletionContext) -> Option<Type> {
1279 if context.scope.kind == ScopeKind::Function {
1281 if context.prefix.contains("Result") {
1283 return Some(Type::new("Result".to_string()));
1284 }
1285 if context.prefix.contains("Option") {
1286 return Some(Type::new("Option".to_string()).optional());
1287 }
1288 if context.prefix.contains("Vec") {
1289 return Some(Type::new("Vec".to_string()).array());
1290 }
1291 if context.prefix.contains("String") {
1292 return Some(Type::new("String".to_string()));
1293 }
1294 }
1295
1296 None
1297 }
1298
1299 fn infer_typescript_return_type(context: &CompletionContext) -> Option<Type> {
1301 if context.scope.kind == ScopeKind::Function {
1303 if context.prefix.contains("Promise") {
1305 return Some(Type::new("Promise".to_string()));
1306 }
1307 if context.prefix.contains("Array") {
1308 return Some(Type::new("Array".to_string()).array());
1309 }
1310 if context.prefix.contains("string") {
1311 return Some(Type::new("string".to_string()));
1312 }
1313 if context.prefix.contains("number") {
1314 return Some(Type::new("number".to_string()));
1315 }
1316 }
1317
1318 None
1319 }
1320
1321 fn infer_python_return_type(context: &CompletionContext) -> Option<Type> {
1323 if context.scope.kind == ScopeKind::Function {
1325 if context.prefix.contains("list") {
1327 return Some(Type::new("list".to_string()).array());
1328 }
1329 if context.prefix.contains("dict") {
1330 return Some(Type::new("dict".to_string()));
1331 }
1332 if context.prefix.contains("str") {
1333 return Some(Type::new("str".to_string()));
1334 }
1335 if context.prefix.contains("int") {
1336 return Some(Type::new("int".to_string()));
1337 }
1338 }
1339
1340 None
1341 }
1342
1343 pub fn infer_variable_type(code: &str, position: Position, language: &str) -> Option<Type> {
1345 let byte_offset = Self::position_to_byte_offset(code, position);
1346 let code_before = &code[..byte_offset];
1347
1348 match language {
1349 "rust" => Self::infer_rust_variable_type(code_before),
1350 "typescript" | "javascript" => Self::infer_typescript_variable_type(code_before),
1351 "python" => Self::infer_python_variable_type(code_before),
1352 _ => None,
1353 }
1354 }
1355
1356 fn infer_rust_variable_type(code_before: &str) -> Option<Type> {
1358 for line in code_before.lines().rev() {
1360 let trimmed = line.trim();
1361
1362 if (trimmed.starts_with("let ") || trimmed.starts_with("let mut "))
1364 && trimmed.contains(':')
1365 {
1366 if let Some(type_str) = Self::extract_rust_type_annotation(trimmed) {
1367 return Some(Self::parse_rust_type(&type_str));
1368 }
1369 }
1370
1371 if trimmed.starts_with("const ") && trimmed.contains(':') {
1373 if let Some(type_str) = Self::extract_rust_type_annotation(trimmed) {
1374 return Some(Self::parse_rust_type(&type_str));
1375 }
1376 }
1377 }
1378
1379 None
1380 }
1381
1382 fn extract_rust_type_annotation(line: &str) -> Option<String> {
1384 if let Some(colon_pos) = line.find(':') {
1385 if let Some(eq_pos) = line.find('=') {
1386 if colon_pos < eq_pos {
1387 let type_str = &line[colon_pos + 1..eq_pos];
1388 return Some(type_str.trim().to_string());
1389 }
1390 } else {
1391 let type_str = &line[colon_pos + 1..];
1392 return Some(type_str.trim().to_string());
1393 }
1394 }
1395 None
1396 }
1397
1398 fn parse_rust_type(type_str: &str) -> Type {
1400 let type_str = type_str.trim();
1401
1402 if type_str.starts_with("Option<") {
1404 let inner = &type_str[7..type_str.len() - 1];
1405 return Type::new(inner.to_string()).optional();
1406 }
1407
1408 if type_str.starts_with("Vec<") {
1410 let inner = &type_str[4..type_str.len() - 1];
1411 return Type::new(inner.to_string()).array();
1412 }
1413
1414 if type_str.starts_with("Result<") {
1416 let inner = &type_str[7..type_str.len() - 1];
1417 return Type::new(inner.to_string());
1418 }
1419
1420 if let Some(inner) = type_str.strip_prefix("&") {
1422 return Type::new(inner.to_string());
1423 }
1424
1425 Type::new(type_str.to_string())
1427 }
1428
1429 fn infer_typescript_variable_type(code_before: &str) -> Option<Type> {
1431 for line in code_before.lines().rev() {
1433 let trimmed = line.trim();
1434
1435 if (trimmed.starts_with("let ")
1437 || trimmed.starts_with("const ")
1438 || trimmed.starts_with("var "))
1439 && trimmed.contains(':')
1440 {
1441 if let Some(type_str) = Self::extract_typescript_type_annotation(trimmed) {
1442 return Some(Self::parse_typescript_type(&type_str));
1443 }
1444 }
1445 }
1446
1447 None
1448 }
1449
1450 fn extract_typescript_type_annotation(line: &str) -> Option<String> {
1452 if let Some(colon_pos) = line.find(':') {
1453 if let Some(eq_pos) = line.find('=') {
1454 if colon_pos < eq_pos {
1455 let type_str = &line[colon_pos + 1..eq_pos];
1456 return Some(type_str.trim().to_string());
1457 }
1458 } else {
1459 let type_str = &line[colon_pos + 1..];
1460 return Some(type_str.trim().to_string());
1461 }
1462 }
1463 None
1464 }
1465
1466 fn parse_typescript_type(type_str: &str) -> Type {
1468 let type_str = type_str.trim();
1469
1470 if type_str.starts_with("Array<") {
1472 let inner = &type_str[6..type_str.len() - 1];
1473 return Type::new(inner.to_string()).array();
1474 }
1475
1476 if let Some(inner) = type_str.strip_suffix("[]") {
1478 return Type::new(inner.to_string()).array();
1479 }
1480
1481 if type_str.starts_with("Promise<") {
1483 let inner = &type_str[8..type_str.len() - 1];
1484 return Type::new(inner.to_string());
1485 }
1486
1487 Type::new(type_str.to_string())
1489 }
1490
1491 fn infer_python_variable_type(code_before: &str) -> Option<Type> {
1493 for line in code_before.lines().rev() {
1495 let trimmed = line.trim();
1496
1497 if trimmed.is_empty() || trimmed.starts_with('#') {
1499 continue;
1500 }
1501
1502 if trimmed.contains(':') && trimmed.contains('=') {
1504 if let Some(type_str) = Self::extract_python_type_annotation(trimmed) {
1505 return Some(Self::parse_python_type(&type_str));
1506 }
1507 }
1508 }
1509
1510 None
1511 }
1512
1513 fn extract_python_type_annotation(line: &str) -> Option<String> {
1515 if let Some(colon_pos) = line.find(':') {
1516 if let Some(eq_pos) = line.find('=') {
1517 if colon_pos < eq_pos {
1518 let type_str = &line[colon_pos + 1..eq_pos];
1519 return Some(type_str.trim().to_string());
1520 }
1521 }
1522 }
1523 None
1524 }
1525
1526 fn parse_python_type(type_str: &str) -> Type {
1528 let type_str = type_str.trim();
1529
1530 if type_str.starts_with("List[") {
1532 let inner = &type_str[5..type_str.len() - 1];
1533 return Type::new(inner.to_string()).array();
1534 }
1535
1536 if type_str == "list" {
1538 return Type::new("list".to_string()).array();
1539 }
1540
1541 if type_str.starts_with("Dict[") {
1543 let inner = &type_str[5..type_str.len() - 1];
1544 return Type::new(inner.to_string());
1545 }
1546
1547 if type_str.starts_with("Optional[") {
1549 let inner = &type_str[9..type_str.len() - 1];
1550 return Type::new(inner.to_string()).optional();
1551 }
1552
1553 if type_str.starts_with("Tuple[") {
1555 let inner = &type_str[6..type_str.len() - 1];
1556 return Type::new(inner.to_string()).array();
1557 }
1558
1559 Type::new(type_str.to_string())
1561 }
1562
1563 pub fn infer_function_return_type(
1565 code: &str,
1566 position: Position,
1567 language: &str,
1568 ) -> Option<Type> {
1569 let byte_offset = Self::position_to_byte_offset(code, position);
1570 let code_before = &code[..byte_offset];
1571
1572 match language {
1573 "rust" => Self::infer_rust_function_return_type(code_before),
1574 "typescript" | "javascript" => Self::infer_typescript_function_return_type(code_before),
1575 "python" => Self::infer_python_function_return_type(code_before),
1576 _ => None,
1577 }
1578 }
1579
1580 fn infer_rust_function_return_type(code_before: &str) -> Option<Type> {
1582 for line in code_before.lines().rev() {
1584 let trimmed = line.trim();
1585
1586 if trimmed.starts_with("fn ") && trimmed.contains("->") {
1588 if let Some(return_type) = Self::extract_rust_return_type(trimmed) {
1589 return Some(Self::parse_rust_type(&return_type));
1590 }
1591 }
1592 }
1593
1594 None
1595 }
1596
1597 fn extract_rust_return_type(line: &str) -> Option<String> {
1599 if let Some(arrow_pos) = line.find("->") {
1600 if let Some(brace_pos) = line.find('{') {
1601 let return_type = &line[arrow_pos + 2..brace_pos];
1602 return Some(return_type.trim().to_string());
1603 } else {
1604 let return_type = &line[arrow_pos + 2..];
1605 return Some(return_type.trim().to_string());
1606 }
1607 }
1608 None
1609 }
1610
1611 fn infer_typescript_function_return_type(code_before: &str) -> Option<Type> {
1613 for line in code_before.lines().rev() {
1615 let trimmed = line.trim();
1616
1617 if (trimmed.starts_with("function ")
1619 || trimmed.starts_with("async function ")
1620 || trimmed.contains("=>"))
1621 && trimmed.contains(':')
1622 {
1623 if let Some(return_type) = Self::extract_typescript_return_type(trimmed) {
1624 return Some(Self::parse_typescript_type(&return_type));
1625 }
1626 }
1627 }
1628
1629 None
1630 }
1631
1632 fn extract_typescript_return_type(line: &str) -> Option<String> {
1634 if let Some(paren_pos) = line.rfind(')') {
1636 let after_paren = &line[paren_pos..];
1637
1638 if let Some(colon_pos) = after_paren.find(':') {
1640 let after_colon = &after_paren[colon_pos + 1..];
1641
1642 let end_pos = if let Some(brace_pos) = after_colon.find('{') {
1644 brace_pos
1645 } else if let Some(arrow_pos) = after_colon.find("=>") {
1646 arrow_pos
1647 } else {
1648 after_colon.len()
1650 };
1651
1652 let return_type = &after_colon[..end_pos];
1653 return Some(return_type.trim().to_string());
1654 }
1655 }
1656 None
1657 }
1658
1659 fn infer_python_function_return_type(code_before: &str) -> Option<Type> {
1661 for line in code_before.lines().rev() {
1663 let trimmed = line.trim();
1664
1665 if trimmed.starts_with("def ") && trimmed.contains("->") {
1667 if let Some(return_type) = Self::extract_python_return_type(trimmed) {
1668 return Some(Self::parse_python_type(&return_type));
1669 }
1670 }
1671 }
1672
1673 None
1674 }
1675
1676 fn extract_python_return_type(line: &str) -> Option<String> {
1678 if let Some(arrow_pos) = line.find("->") {
1679 if let Some(colon_pos) = line.find(':') {
1680 if arrow_pos < colon_pos {
1681 let return_type = &line[arrow_pos + 2..colon_pos];
1682 return Some(return_type.trim().to_string());
1683 }
1684 }
1685 }
1686 None
1687 }
1688}
1689
1690pub struct GenericContextAnalyzer;
1692
1693impl GenericContextAnalyzer {
1694 fn collect_imported_symbols_generic(code: &str, language: &str) -> Vec<Symbol> {
1696 let mut symbols = Vec::new();
1697
1698 match language {
1699 "rust" => {
1700 for line in code.lines() {
1702 if line.trim().starts_with("use ") {
1703 if let Some(imported) = TreeSitterContextAnalyzer::extract_rust_import(line)
1704 {
1705 symbols.push(Symbol {
1706 name: imported.clone(),
1707 kind: SymbolKind::Module,
1708 scope: Scope {
1709 kind: ScopeKind::Global,
1710 name: None,
1711 range: Range::new(Position::new(0, 0), Position::new(0, 0)),
1712 },
1713 type_info: None,
1714 documentation: None,
1715 });
1716 }
1717 }
1718 }
1719 }
1720 "typescript" | "javascript" => {
1721 for line in code.lines() {
1723 if line.trim().starts_with("import ") {
1724 if let Some(imported) =
1725 TreeSitterContextAnalyzer::extract_typescript_import(line)
1726 {
1727 symbols.push(Symbol {
1728 name: imported.clone(),
1729 kind: SymbolKind::Module,
1730 scope: Scope {
1731 kind: ScopeKind::Global,
1732 name: None,
1733 range: Range::new(Position::new(0, 0), Position::new(0, 0)),
1734 },
1735 type_info: None,
1736 documentation: None,
1737 });
1738 }
1739 }
1740 }
1741 }
1742 "python" => {
1743 for line in code.lines() {
1745 if line.trim().starts_with("import ") || line.trim().starts_with("from ") {
1746 if let Some(imported) =
1747 TreeSitterContextAnalyzer::extract_python_import(line)
1748 {
1749 symbols.push(Symbol {
1750 name: imported.clone(),
1751 kind: SymbolKind::Module,
1752 scope: Scope {
1753 kind: ScopeKind::Global,
1754 name: None,
1755 range: Range::new(Position::new(0, 0), Position::new(0, 0)),
1756 },
1757 type_info: None,
1758 documentation: None,
1759 });
1760 }
1761 }
1762 }
1763 }
1764 _ => {}
1765 }
1766
1767 symbols
1768 }
1769
1770 fn collect_scope_symbols_generic(context: &CompletionContext, code: &str) -> Vec<Symbol> {
1772 let mut symbols = Vec::new();
1773
1774 match context.language.as_str() {
1775 "rust" => {
1776 symbols.extend(TreeSitterContextAnalyzer::collect_rust_scope_symbols(
1777 code, context,
1778 ));
1779 }
1780 "typescript" | "javascript" => {
1781 symbols.extend(TreeSitterContextAnalyzer::collect_typescript_scope_symbols(
1782 code, context,
1783 ));
1784 }
1785 "python" => {
1786 symbols.extend(TreeSitterContextAnalyzer::collect_python_scope_symbols(
1787 code, context,
1788 ));
1789 }
1790 _ => {}
1791 }
1792
1793 symbols
1794 }
1795}
1796
1797#[async_trait]
1798impl ContextAnalyzer for GenericContextAnalyzer {
1799 async fn analyze_context(
1800 &self,
1801 code: &str,
1802 position: Position,
1803 language: &str,
1804 ) -> CompletionResult<CompletionContext> {
1805 let prefix = Self::extract_prefix_generic(code, position);
1807
1808 let mut context = CompletionContext::new(language.to_string(), position, prefix);
1810
1811 context.scope = Self::detect_scope_generic(code, position);
1813
1814 context.available_symbols = self.get_available_symbols(&context, code);
1816
1817 context.expected_type = self.infer_expected_type(&context);
1819
1820 Ok(context)
1821 }
1822
1823 fn get_available_symbols(&self, context: &CompletionContext, code: &str) -> Vec<Symbol> {
1824 let mut symbols = Vec::new();
1826
1827 symbols.extend(Self::get_builtin_symbols(&context.language));
1829
1830 symbols.extend(Self::collect_imported_symbols_generic(
1832 code,
1833 &context.language,
1834 ));
1835
1836 symbols.extend(Self::collect_scope_symbols_generic(context, code));
1838
1839 symbols
1840 }
1841
1842 fn infer_expected_type(&self, context: &CompletionContext) -> Option<Type> {
1843 Self::infer_type_from_context_generic(context)
1844 }
1845}
1846
1847impl GenericContextAnalyzer {
1848 fn infer_type_from_context_generic(context: &CompletionContext) -> Option<Type> {
1850 if let Some(type_info) = Self::infer_from_assignment_generic(context) {
1852 return Some(type_info);
1853 }
1854
1855 if let Some(type_info) = Self::infer_from_function_param_generic(context) {
1857 return Some(type_info);
1858 }
1859
1860 if let Some(type_info) = Self::infer_from_return_type_generic(context) {
1862 return Some(type_info);
1863 }
1864
1865 None
1866 }
1867
1868 fn infer_from_assignment_generic(context: &CompletionContext) -> Option<Type> {
1870 match context.language.as_str() {
1871 "rust" => TreeSitterContextAnalyzer::infer_rust_assignment_type(context),
1872 "typescript" | "javascript" => {
1873 TreeSitterContextAnalyzer::infer_typescript_assignment_type(context)
1874 }
1875 "python" => TreeSitterContextAnalyzer::infer_python_assignment_type(context),
1876 _ => None,
1877 }
1878 }
1879
1880 fn infer_from_function_param_generic(context: &CompletionContext) -> Option<Type> {
1882 match context.language.as_str() {
1883 "rust" => TreeSitterContextAnalyzer::infer_rust_function_param_type(context),
1884 "typescript" | "javascript" => {
1885 TreeSitterContextAnalyzer::infer_typescript_function_param_type(context)
1886 }
1887 "python" => TreeSitterContextAnalyzer::infer_python_function_param_type(context),
1888 _ => None,
1889 }
1890 }
1891
1892 fn infer_from_return_type_generic(context: &CompletionContext) -> Option<Type> {
1894 match context.language.as_str() {
1895 "rust" => TreeSitterContextAnalyzer::infer_rust_return_type(context),
1896 "typescript" | "javascript" => {
1897 TreeSitterContextAnalyzer::infer_typescript_return_type(context)
1898 }
1899 "python" => TreeSitterContextAnalyzer::infer_python_return_type(context),
1900 _ => None,
1901 }
1902 }
1903 fn extract_prefix_generic(code: &str, position: Position) -> String {
1905 let byte_offset = TreeSitterContextAnalyzer::position_to_byte_offset(code, position);
1906 let mut prefix = String::new();
1907
1908 for ch in code[..byte_offset].chars().rev() {
1910 if ch.is_alphanumeric() || ch == '_' {
1911 prefix.insert(0, ch);
1912 } else {
1913 break;
1914 }
1915 }
1916
1917 prefix
1918 }
1919
1920 fn detect_scope_generic(code: &str, position: Position) -> Scope {
1922 let byte_offset = TreeSitterContextAnalyzer::position_to_byte_offset(code, position);
1923 let code_before = &code[..byte_offset];
1924
1925 let open_braces = code_before.matches('{').count();
1927 let close_braces = code_before.matches('}').count();
1928 let in_block = open_braces > close_braces;
1929
1930 let scope_kind = if code_before.contains("fn ") || code_before.contains("function ") {
1932 ScopeKind::Function
1933 } else if code_before.contains("class ") || code_before.contains("struct ") {
1934 ScopeKind::Class
1935 } else if in_block {
1936 ScopeKind::Block
1937 } else {
1938 ScopeKind::Global
1939 };
1940
1941 Scope {
1942 kind: scope_kind,
1943 name: None,
1944 range: Range::new(Position::new(0, 0), position),
1945 }
1946 }
1947
1948 fn get_builtin_symbols(language: &str) -> Vec<Symbol> {
1950 TreeSitterContextAnalyzer::get_builtin_symbols(language)
1951 }
1952}
1953
1954#[cfg(test)]
1955mod tests {
1956 use super::*;
1957
1958 #[test]
1959 fn test_position_to_byte_offset() {
1960 let code = "hello\nworld";
1961 let pos = Position::new(1, 2);
1962 let offset = TreeSitterContextAnalyzer::position_to_byte_offset(code, pos);
1963 assert_eq!(offset, 8); }
1965
1966 #[test]
1967 fn test_byte_offset_to_position() {
1968 let code = "hello\nworld";
1969 let pos = TreeSitterContextAnalyzer::byte_offset_to_position(code, 8);
1970 assert_eq!(pos, Position::new(1, 2));
1971 }
1972
1973 #[test]
1974 fn test_extract_prefix() {
1975 let code = "let my_var = ";
1976 let pos = Position::new(0, 13);
1977 let prefix = TreeSitterContextAnalyzer::extract_prefix(code, pos);
1978 assert_eq!(prefix, "");
1979 }
1980
1981 #[test]
1982 fn test_extract_prefix_with_word() {
1983 let code = "let my_var = my";
1984 let pos = Position::new(0, 15);
1985 let prefix = TreeSitterContextAnalyzer::extract_prefix(code, pos);
1986 assert_eq!(prefix, "my");
1987 }
1988
1989 #[test]
1990 fn test_generic_extract_prefix() {
1991 let code = "let my_var = my";
1992 let pos = Position::new(0, 15);
1993 let prefix = GenericContextAnalyzer::extract_prefix_generic(code, pos);
1994 assert_eq!(prefix, "my");
1995 }
1996
1997 #[test]
1998 fn test_generic_detect_scope_global() {
1999 let code = "let x = 5;";
2000 let pos = Position::new(0, 5);
2001 let scope = GenericContextAnalyzer::detect_scope_generic(code, pos);
2002 assert_eq!(scope.kind, ScopeKind::Global);
2003 }
2004
2005 #[test]
2006 fn test_generic_detect_scope_function() {
2007 let code = "fn main() { let x = 5; }";
2008 let pos = Position::new(0, 15);
2009 let scope = GenericContextAnalyzer::detect_scope_generic(code, pos);
2010 assert_eq!(scope.kind, ScopeKind::Function);
2011 }
2012
2013 #[test]
2014 fn test_generic_detect_scope_block() {
2015 let code = "{ let x = 5; }";
2016 let pos = Position::new(0, 10);
2017 let scope = GenericContextAnalyzer::detect_scope_generic(code, pos);
2018 assert_eq!(scope.kind, ScopeKind::Block);
2019 }
2020
2021 #[test]
2023 fn test_infer_rust_variable_type_simple() {
2024 let code = "let x: String = ";
2025 let ty = TreeSitterContextAnalyzer::infer_rust_variable_type(code);
2026 assert!(ty.is_some());
2027 let ty = ty.unwrap();
2028 assert_eq!(ty.name, "String");
2029 }
2030
2031 #[test]
2032 fn test_infer_rust_variable_type_vec() {
2033 let code = "let items: Vec<i32> = ";
2034 let ty = TreeSitterContextAnalyzer::infer_rust_variable_type(code);
2035 assert!(ty.is_some());
2036 let ty = ty.unwrap();
2037 assert_eq!(ty.name, "i32");
2038 assert!(ty.is_array);
2039 }
2040
2041 #[test]
2042 fn test_infer_rust_variable_type_option() {
2043 let code = "let maybe: Option<String> = ";
2044 let ty = TreeSitterContextAnalyzer::infer_rust_variable_type(code);
2045 assert!(ty.is_some());
2046 let ty = ty.unwrap();
2047 assert_eq!(ty.name, "String");
2048 assert!(ty.is_optional);
2049 }
2050
2051 #[test]
2052 fn test_infer_rust_variable_type_reference() {
2053 let code = "let reference: &str = ";
2054 let ty = TreeSitterContextAnalyzer::infer_rust_variable_type(code);
2055 assert!(ty.is_some());
2056 let ty = ty.unwrap();
2057 assert_eq!(ty.name, "str");
2058 }
2059
2060 #[test]
2061 fn test_infer_typescript_variable_type_simple() {
2062 let code = "let x: string = ";
2063 let ty = TreeSitterContextAnalyzer::infer_typescript_variable_type(code);
2064 assert!(ty.is_some());
2065 let ty = ty.unwrap();
2066 assert_eq!(ty.name, "string");
2067 }
2068
2069 #[test]
2070 fn test_infer_typescript_variable_type_array() {
2071 let code = "let items: number[] = ";
2072 let ty = TreeSitterContextAnalyzer::infer_typescript_variable_type(code);
2073 assert!(ty.is_some());
2074 let ty = ty.unwrap();
2075 assert_eq!(ty.name, "number");
2076 assert!(ty.is_array);
2077 }
2078
2079 #[test]
2080 fn test_infer_typescript_variable_type_array_generic() {
2081 let code = "let items: Array<string> = ";
2082 let ty = TreeSitterContextAnalyzer::infer_typescript_variable_type(code);
2083 assert!(ty.is_some());
2084 let ty = ty.unwrap();
2085 assert_eq!(ty.name, "string");
2086 assert!(ty.is_array);
2087 }
2088
2089 #[test]
2090 fn test_infer_python_variable_type_simple() {
2091 let code = "x: str = ";
2092 let ty = TreeSitterContextAnalyzer::infer_python_variable_type(code);
2093 assert!(ty.is_some());
2094 let ty = ty.unwrap();
2095 assert_eq!(ty.name, "str");
2096 }
2097
2098 #[test]
2099 fn test_infer_python_variable_type_list() {
2100 let code = "items: List[int] = ";
2101 let ty = TreeSitterContextAnalyzer::infer_python_variable_type(code);
2102 assert!(ty.is_some());
2103 let ty = ty.unwrap();
2104 assert_eq!(ty.name, "int");
2105 assert!(ty.is_array);
2106 }
2107
2108 #[test]
2109 fn test_infer_python_variable_type_optional() {
2110 let code = "maybe: Optional[str] = ";
2111 let ty = TreeSitterContextAnalyzer::infer_python_variable_type(code);
2112 assert!(ty.is_some());
2113 let ty = ty.unwrap();
2114 assert_eq!(ty.name, "str");
2115 assert!(ty.is_optional);
2116 }
2117
2118 #[test]
2119 fn test_infer_rust_function_return_type() {
2120 let code = "fn get_name() -> String { ";
2121 let ty = TreeSitterContextAnalyzer::infer_rust_function_return_type(code);
2122 assert!(ty.is_some());
2123 let ty = ty.unwrap();
2124 assert_eq!(ty.name, "String");
2125 }
2126
2127 #[test]
2128 fn test_infer_rust_function_return_type_result() {
2129 let code = "fn process() -> Result<i32, String> { ";
2130 let ty = TreeSitterContextAnalyzer::infer_rust_function_return_type(code);
2131 assert!(ty.is_some());
2132 let ty = ty.unwrap();
2133 assert_eq!(ty.name, "i32, String");
2134 }
2135
2136 #[test]
2137 fn test_infer_typescript_function_return_type() {
2138 let code = "function getName(): string { ";
2139 let ty = TreeSitterContextAnalyzer::infer_typescript_function_return_type(code);
2140 assert!(ty.is_some());
2141 let ty = ty.unwrap();
2142 assert_eq!(ty.name, "string");
2143 }
2144
2145 #[test]
2146 fn test_infer_typescript_function_return_type_promise() {
2147 let code = "async function fetch(): Promise<string> { ";
2148 let ty = TreeSitterContextAnalyzer::infer_typescript_function_return_type(code);
2149 assert!(ty.is_some());
2150 let ty = ty.unwrap();
2151 assert_eq!(ty.name, "string");
2152 }
2153
2154 #[test]
2155 fn test_infer_python_function_return_type() {
2156 let code = "def get_name() -> str: ";
2157 let ty = TreeSitterContextAnalyzer::infer_python_function_return_type(code);
2158 assert!(ty.is_some());
2159 let ty = ty.unwrap();
2160 assert_eq!(ty.name, "str");
2161 }
2162
2163 #[test]
2164 fn test_infer_python_function_return_type_list() {
2165 let code = "def get_items() -> List[int]: ";
2166 let ty = TreeSitterContextAnalyzer::infer_python_function_return_type(code);
2167 assert!(ty.is_some());
2168 let ty = ty.unwrap();
2169 assert_eq!(ty.name, "int");
2170 assert!(ty.is_array);
2171 }
2172
2173 #[test]
2174 fn test_parse_rust_type_simple() {
2175 let ty = TreeSitterContextAnalyzer::parse_rust_type("String");
2176 assert_eq!(ty.name, "String");
2177 assert!(!ty.is_optional);
2178 assert!(!ty.is_array);
2179 }
2180
2181 #[test]
2182 fn test_parse_rust_type_vec() {
2183 let ty = TreeSitterContextAnalyzer::parse_rust_type("Vec<i32>");
2184 assert_eq!(ty.name, "i32");
2185 assert!(ty.is_array);
2186 }
2187
2188 #[test]
2189 fn test_parse_rust_type_option() {
2190 let ty = TreeSitterContextAnalyzer::parse_rust_type("Option<String>");
2191 assert_eq!(ty.name, "String");
2192 assert!(ty.is_optional);
2193 }
2194
2195 #[test]
2196 fn test_parse_typescript_type_array() {
2197 let ty = TreeSitterContextAnalyzer::parse_typescript_type("string[]");
2198 assert_eq!(ty.name, "string");
2199 assert!(ty.is_array);
2200 }
2201
2202 #[test]
2203 fn test_parse_typescript_type_array_generic() {
2204 let ty = TreeSitterContextAnalyzer::parse_typescript_type("Array<number>");
2205 assert_eq!(ty.name, "number");
2206 assert!(ty.is_array);
2207 }
2208
2209 #[test]
2210 fn test_parse_python_type_list() {
2211 let ty = TreeSitterContextAnalyzer::parse_python_type("List[str]");
2212 assert_eq!(ty.name, "str");
2213 assert!(ty.is_array);
2214 }
2215
2216 #[test]
2217 fn test_parse_python_type_optional() {
2218 let ty = TreeSitterContextAnalyzer::parse_python_type("Optional[int]");
2219 assert_eq!(ty.name, "int");
2220 assert!(ty.is_optional);
2221 }
2222
2223 #[test]
2224 fn test_extract_rust_type_annotation() {
2225 let line = "let x: String = value;";
2226 let ty = TreeSitterContextAnalyzer::extract_rust_type_annotation(line);
2227 assert!(ty.is_some());
2228 assert_eq!(ty.unwrap(), "String");
2229 }
2230
2231 #[test]
2232 fn test_extract_rust_type_annotation_complex() {
2233 let line = "let items: Vec<i32> = vec![];";
2234 let ty = TreeSitterContextAnalyzer::extract_rust_type_annotation(line);
2235 assert!(ty.is_some());
2236 assert_eq!(ty.unwrap(), "Vec<i32>");
2237 }
2238
2239 #[test]
2240 fn test_extract_typescript_type_annotation() {
2241 let line = "let x: string = value;";
2242 let ty = TreeSitterContextAnalyzer::extract_typescript_type_annotation(line);
2243 assert!(ty.is_some());
2244 assert_eq!(ty.unwrap(), "string");
2245 }
2246
2247 #[test]
2248 fn test_extract_python_type_annotation() {
2249 let line = "x: str = value";
2250 let ty = TreeSitterContextAnalyzer::extract_python_type_annotation(line);
2251 assert!(ty.is_some());
2252 assert_eq!(ty.unwrap(), "str");
2253 }
2254}