Skip to main content

vtcode_core/code/code_completion/context/
analyzer.rs

1use super::CompletionContext;
2
3/// Context analyzer for understanding code context
4pub struct ContextAnalyzer;
5
6impl ContextAnalyzer {
7    pub fn new() -> Self {
8        Self
9    }
10
11    /// Analyze code context at the given position
12    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::") || first_lines.contains("fn ") && first_lines.contains("->") {
27            "rust".into()
28        } else if first_lines.contains("import ") && first_lines.contains("from ") || first_lines.contains("def ") {
29            "python".into()
30        } else if first_lines.contains("interface ")
31            || first_lines.contains(": string")
32            || first_lines.contains(": number")
33        {
34            "typescript".into()
35        } else if first_lines.contains("function ")
36            || first_lines.contains("const ")
37            || first_lines.contains("require(")
38        {
39            "javascript".into()
40        } else if first_lines.contains("package ") && first_lines.contains("func ") {
41            "go".into()
42        } else if first_lines.contains("public class ") || first_lines.contains("import java.") {
43            "java".into()
44        } else if first_lines.starts_with("#!/bin/bash") || first_lines.starts_with("#!/bin/sh") {
45            "bash".into()
46        } else {
47            "rust".into()
48        }
49    }
50
51    fn extract_prefix(&self, source: &str, line: usize, column: usize) -> String {
52        let lines: Vec<&str> = source.lines().collect();
53        if line < lines.len() && column <= lines[line].len() {
54            lines[line][..column].into()
55        } else {
56            String::new()
57        }
58    }
59
60    /// Extract import statements from source code using simple line scanning
61    fn extract_imports(&self, source: &str) -> Vec<String> {
62        source
63            .lines()
64            .filter(|line| {
65                let trimmed = line.trim();
66                trimmed.starts_with("use ")
67                    || trimmed.starts_with("import ")
68                    || trimmed.starts_with("from ")
69                    || trimmed.starts_with("require(")
70                    || trimmed.starts_with("const ") && trimmed.contains("require(")
71            })
72            .map(|s| s.to_string())
73            .collect()
74    }
75}
76
77impl Default for ContextAnalyzer {
78    fn default() -> Self {
79        Self::new()
80    }
81}