use std::path::Path;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ProjectType {
Rust,
Cuda,
Go,
Python,
JavaScript,
TypeScript,
C,
Cpp,
CSharp,
Java,
}
pub fn detect_project_types(dir: &Path) -> Vec<ProjectType> {
let mut types = Vec::new();
if dir.join("Cargo.toml").exists() {
types.push(ProjectType::Rust);
}
if has_extension_in_dir(dir, "cu") {
types.push(ProjectType::Cuda);
}
if dir.join("go.mod").exists() || dir.join("go.sum").exists() {
types.push(ProjectType::Go);
}
if dir.join("pyproject.toml").exists()
|| dir.join("setup.py").exists()
|| dir.join("requirements.txt").exists()
|| dir.join("Pipfile").exists()
{
types.push(ProjectType::Python);
}
if dir.join("package.json").exists() {
if dir.join("tsconfig.json").exists() {
types.push(ProjectType::TypeScript);
} else {
types.push(ProjectType::JavaScript);
}
}
if dir.join("CMakeLists.txt").exists()
|| dir.join("Makefile").exists()
|| dir.join("configure").exists()
|| dir.join("meson.build").exists()
{
if has_cpp_files(dir) {
types.push(ProjectType::Cpp);
} else if has_c_files(dir) {
types.push(ProjectType::C);
} else {
types.push(ProjectType::Cpp);
}
}
if has_extension_in_dir(dir, "csproj") || has_extension_in_dir(dir, "sln") {
types.push(ProjectType::CSharp);
}
if dir.join("pom.xml").exists()
|| dir.join("build.gradle").exists()
|| dir.join("build.gradle.kts").exists()
{
types.push(ProjectType::Java);
}
types
}
pub fn debuggers_for_project(project: &ProjectType) -> Vec<&'static str> {
match project {
ProjectType::Rust => vec!["codelldb", "lldb"],
ProjectType::Cuda => vec!["cuda-gdb"],
ProjectType::Go => vec!["go"],
ProjectType::Python => vec!["python"],
ProjectType::JavaScript | ProjectType::TypeScript => vec!["js-debug"],
ProjectType::C | ProjectType::Cpp => vec!["lldb", "codelldb"],
ProjectType::CSharp => vec![], ProjectType::Java => vec![], }
}
fn has_cpp_files(dir: &Path) -> bool {
has_extension_in_dir(dir, "cpp")
|| has_extension_in_dir(dir, "cc")
|| has_extension_in_dir(dir, "cxx")
|| has_extension_in_dir(dir, "hpp")
|| has_extension_in_dir(dir, "hxx")
}
fn has_c_files(dir: &Path) -> bool {
has_extension_in_dir(dir, "c") || has_extension_in_dir(dir, "h")
}
fn has_extension_in_dir(dir: &Path, ext: &str) -> bool {
if let Ok(entries) = std::fs::read_dir(dir) {
for entry in entries {
if let Ok(entry) = entry {
let path = entry.path();
if path.extension().map(|e| e == ext).unwrap_or(false) {
return true;
}
}
}
}
false
}
#[cfg(test)]
mod tests {
use super::*;
use tempfile::tempdir;
#[test]
fn test_detect_rust_project() {
let dir = tempdir().unwrap();
std::fs::write(dir.path().join("Cargo.toml"), "[package]").unwrap();
let types = detect_project_types(dir.path());
assert!(types.contains(&ProjectType::Rust));
}
#[test]
fn test_detect_python_project() {
let dir = tempdir().unwrap();
std::fs::write(dir.path().join("requirements.txt"), "requests").unwrap();
let types = detect_project_types(dir.path());
assert!(types.contains(&ProjectType::Python));
}
#[test]
fn test_debuggers_for_rust() {
let debuggers = debuggers_for_project(&ProjectType::Rust);
assert!(debuggers.contains(&"codelldb"));
}
}