debugger/setup/
detector.rs1use std::path::Path;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
9pub enum ProjectType {
10 Rust,
11 Go,
12 Python,
13 JavaScript,
14 TypeScript,
15 C,
16 Cpp,
17 CSharp,
18 Java,
19}
20
21pub fn detect_project_types(dir: &Path) -> Vec<ProjectType> {
23 let mut types = Vec::new();
24
25 if dir.join("Cargo.toml").exists() {
27 types.push(ProjectType::Rust);
28 }
29
30 if dir.join("go.mod").exists() || dir.join("go.sum").exists() {
32 types.push(ProjectType::Go);
33 }
34
35 if dir.join("pyproject.toml").exists()
37 || dir.join("setup.py").exists()
38 || dir.join("requirements.txt").exists()
39 || dir.join("Pipfile").exists()
40 {
41 types.push(ProjectType::Python);
42 }
43
44 if dir.join("package.json").exists() {
46 if dir.join("tsconfig.json").exists() {
48 types.push(ProjectType::TypeScript);
49 } else {
50 types.push(ProjectType::JavaScript);
51 }
52 }
53
54 if dir.join("CMakeLists.txt").exists()
56 || dir.join("Makefile").exists()
57 || dir.join("configure").exists()
58 || dir.join("meson.build").exists()
59 {
60 if has_cpp_files(dir) {
62 types.push(ProjectType::Cpp);
63 } else if has_c_files(dir) {
64 types.push(ProjectType::C);
65 } else {
66 types.push(ProjectType::Cpp);
68 }
69 }
70
71 if has_extension_in_dir(dir, "csproj") || has_extension_in_dir(dir, "sln") {
73 types.push(ProjectType::CSharp);
74 }
75
76 if dir.join("pom.xml").exists()
78 || dir.join("build.gradle").exists()
79 || dir.join("build.gradle.kts").exists()
80 {
81 types.push(ProjectType::Java);
82 }
83
84 types
85}
86
87pub fn debuggers_for_project(project: &ProjectType) -> Vec<&'static str> {
89 match project {
90 ProjectType::Rust => vec!["codelldb", "lldb"],
91 ProjectType::Go => vec!["go"],
92 ProjectType::Python => vec!["python"],
93 ProjectType::JavaScript | ProjectType::TypeScript => vec![], ProjectType::C | ProjectType::Cpp => vec!["lldb", "codelldb"],
95 ProjectType::CSharp => vec![], ProjectType::Java => vec![], }
98}
99
100fn has_cpp_files(dir: &Path) -> bool {
102 has_extension_in_dir(dir, "cpp")
103 || has_extension_in_dir(dir, "cc")
104 || has_extension_in_dir(dir, "cxx")
105 || has_extension_in_dir(dir, "hpp")
106 || has_extension_in_dir(dir, "hxx")
107}
108
109fn has_c_files(dir: &Path) -> bool {
111 has_extension_in_dir(dir, "c") || has_extension_in_dir(dir, "h")
112}
113
114fn has_extension_in_dir(dir: &Path, ext: &str) -> bool {
116 if let Ok(entries) = std::fs::read_dir(dir) {
117 for entry in entries {
118 if let Ok(entry) = entry {
120 let path = entry.path();
121 if path.extension().map(|e| e == ext).unwrap_or(false) {
122 return true;
123 }
124 }
125 }
126 }
127 false
128}
129
130#[cfg(test)]
131mod tests {
132 use super::*;
133 use tempfile::tempdir;
134
135 #[test]
136 fn test_detect_rust_project() {
137 let dir = tempdir().unwrap();
138 std::fs::write(dir.path().join("Cargo.toml"), "[package]").unwrap();
139 let types = detect_project_types(dir.path());
140 assert!(types.contains(&ProjectType::Rust));
141 }
142
143 #[test]
144 fn test_detect_python_project() {
145 let dir = tempdir().unwrap();
146 std::fs::write(dir.path().join("requirements.txt"), "requests").unwrap();
147 let types = detect_project_types(dir.path());
148 assert!(types.contains(&ProjectType::Python));
149 }
150
151 #[test]
152 fn test_debuggers_for_rust() {
153 let debuggers = debuggers_for_project(&ProjectType::Rust);
154 assert!(debuggers.contains(&"codelldb"));
155 }
156}