use std::collections::HashSet;
use std::path::Path;
use once_cell::sync::Lazy;
use tree_sitter::Language;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum FileCategory {
Code,
Document,
}
#[derive(Debug, Clone)]
pub struct FileType {
pub language: &'static str,
pub category: FileCategory,
}
static FILE_TYPES: Lazy<Vec<(&'static str, FileType)>> = Lazy::new(|| {
vec![
(
".py",
FileType {
language: "python",
category: FileCategory::Code,
},
),
(
".js",
FileType {
language: "javascript",
category: FileCategory::Code,
},
),
(
".jsx",
FileType {
language: "jsx",
category: FileCategory::Code,
},
),
(
".ts",
FileType {
language: "typescript",
category: FileCategory::Code,
},
),
(
".tsx",
FileType {
language: "tsx",
category: FileCategory::Code,
},
),
(
".go",
FileType {
language: "go",
category: FileCategory::Code,
},
),
(
".rs",
FileType {
language: "rust",
category: FileCategory::Code,
},
),
(
".java",
FileType {
language: "java",
category: FileCategory::Code,
},
),
(
".kt",
FileType {
language: "kotlin",
category: FileCategory::Code,
},
),
(
".kts",
FileType {
language: "kotlin",
category: FileCategory::Code,
},
),
(
".rb",
FileType {
language: "ruby",
category: FileCategory::Code,
},
),
(
".php",
FileType {
language: "php",
category: FileCategory::Code,
},
),
(
".c",
FileType {
language: "c",
category: FileCategory::Code,
},
),
(
".h",
FileType {
language: "c",
category: FileCategory::Code,
},
),
(
".cpp",
FileType {
language: "cpp",
category: FileCategory::Code,
},
),
(
".hpp",
FileType {
language: "cpp",
category: FileCategory::Code,
},
),
(
".cs",
FileType {
language: "csharp",
category: FileCategory::Code,
},
),
(
".swift",
FileType {
language: "swift",
category: FileCategory::Code,
},
),
(
".scala",
FileType {
language: "scala",
category: FileCategory::Code,
},
),
(
".sbt",
FileType {
language: "scala",
category: FileCategory::Code,
},
),
(
".ex",
FileType {
language: "elixir",
category: FileCategory::Code,
},
),
(
".exs",
FileType {
language: "elixir",
category: FileCategory::Code,
},
),
(
".dart",
FileType {
language: "dart",
category: FileCategory::Code,
},
),
(
".lua",
FileType {
language: "lua",
category: FileCategory::Code,
},
),
(
".sql",
FileType {
language: "sql",
category: FileCategory::Code,
},
),
(
".sh",
FileType {
language: "bash",
category: FileCategory::Code,
},
),
(
".bash",
FileType {
language: "bash",
category: FileCategory::Code,
},
),
(
".zig",
FileType {
language: "zig",
category: FileCategory::Code,
},
),
(
".hs",
FileType {
language: "haskell",
category: FileCategory::Code,
},
),
(
".md",
FileType {
language: "markdown",
category: FileCategory::Document,
},
),
(
".yaml",
FileType {
language: "yaml",
category: FileCategory::Document,
},
),
(
".yml",
FileType {
language: "yaml",
category: FileCategory::Document,
},
),
(
".toml",
FileType {
language: "toml",
category: FileCategory::Document,
},
),
(
".json",
FileType {
language: "json",
category: FileCategory::Document,
},
),
]
});
pub fn file_types() -> &'static [(&'static str, FileType)] {
&FILE_TYPES
}
pub fn language_for_path(path: &Path) -> Option<&'static str> {
let ext = path.extension()?.to_str()?;
let dot_ext = format!(".{}", ext.to_lowercase());
file_types()
.iter()
.find(|(e, _)| *e == dot_ext)
.map(|(_, ft)| ft.language)
}
pub fn filter_extensions(
extensions: Option<&HashSet<String>>,
include_text_files: bool,
) -> HashSet<String> {
if let Some(ext) = extensions {
return ext.clone();
}
let mut categories = HashSet::new();
categories.insert(FileCategory::Code);
if include_text_files {
categories.insert(FileCategory::Document);
}
file_types()
.iter()
.filter(|(_, ft)| categories.contains(&ft.category))
.map(|(ext, _)| ext.to_string())
.collect()
}
pub(crate) fn tree_sitter_language(name: &str) -> Option<Language> {
let lang_fn = match name {
"rust" => tree_sitter_rust::LANGUAGE,
"python" => tree_sitter_python::LANGUAGE,
"javascript" | "jsx" => tree_sitter_javascript::LANGUAGE,
"typescript" => tree_sitter_typescript::LANGUAGE_TYPESCRIPT,
"tsx" => tree_sitter_typescript::LANGUAGE_TSX,
"go" => tree_sitter_go::LANGUAGE,
"java" => tree_sitter_java::LANGUAGE,
"c" => tree_sitter_c::LANGUAGE,
"cpp" => tree_sitter_cpp::LANGUAGE,
_ => return None,
};
Some(Language::from(lang_fn))
}
pub(crate) fn is_javascript_like(language: &str) -> bool {
matches!(language, "javascript" | "jsx")
}
pub(crate) fn is_typescript_like(language: &str) -> bool {
matches!(language, "typescript" | "tsx")
}
pub(crate) fn is_js_ts_like(language: &str) -> bool {
is_javascript_like(language) || is_typescript_like(language)
}