vtcode_core/code/code_completion/context/
analyzer.rs1use super::CompletionContext;
2
3pub struct ContextAnalyzer;
5
6impl ContextAnalyzer {
7 pub fn new() -> Self {
8 Self
9 }
10
11 pub fn analyze(&mut self, source: &str, line: usize, column: usize) -> CompletionContext {
13 let language = self.detect_language(source);
14 let prefix = self.extract_prefix(source, line, column);
15
16 let mut context = CompletionContext::new(line, column, prefix, language);
17 context.scope = Vec::new();
18 context.imports = self.extract_imports(source);
19 context.recent_symbols = Vec::new();
20
21 context
22 }
23
24 fn detect_language(&self, source: &str) -> String {
25 let first_lines: String = source.lines().take(20).collect::<Vec<_>>().join("\n");
26 if first_lines.contains("use std::")
27 || first_lines.contains("fn ") && first_lines.contains("->")
28 {
29 "rust".into()
30 } else if first_lines.contains("import ") && first_lines.contains("from ")
31 || first_lines.contains("def ")
32 {
33 "python".into()
34 } else if first_lines.contains("interface ")
35 || first_lines.contains(": string")
36 || first_lines.contains(": number")
37 {
38 "typescript".into()
39 } else if first_lines.contains("function ")
40 || first_lines.contains("const ")
41 || first_lines.contains("require(")
42 {
43 "javascript".into()
44 } else if first_lines.contains("package ") && first_lines.contains("func ") {
45 "go".into()
46 } else if first_lines.contains("public class ") || first_lines.contains("import java.") {
47 "java".into()
48 } else if first_lines.starts_with("#!/bin/bash") || first_lines.starts_with("#!/bin/sh") {
49 "bash".into()
50 } else {
51 "rust".into()
52 }
53 }
54
55 fn extract_prefix(&self, source: &str, line: usize, column: usize) -> String {
56 let lines: Vec<&str> = source.lines().collect();
57 if line < lines.len() && column <= lines[line].len() {
58 lines[line][..column].into()
59 } else {
60 String::new()
61 }
62 }
63
64 fn extract_imports(&self, source: &str) -> Vec<String> {
66 source
67 .lines()
68 .filter(|line| {
69 let trimmed = line.trim();
70 trimmed.starts_with("use ")
71 || trimmed.starts_with("import ")
72 || trimmed.starts_with("from ")
73 || trimmed.starts_with("require(")
74 || trimmed.starts_with("const ") && trimmed.contains("require(")
75 })
76 .map(|s| s.to_string())
77 .collect()
78 }
79}
80
81impl Default for ContextAnalyzer {
82 fn default() -> Self {
83 Self::new()
84 }
85}