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::")
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    /// Extract import statements from source code using simple line scanning
65    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}