use std::collections::HashMap;
use std::path::Path;
use std::sync::OnceLock;
use tree_sitter_tags::TagsConfiguration;
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
pub enum Lang {
Rust,
Python,
JavaScript,
TypeScript,
Tsx,
Go,
Java,
}
impl Lang {
pub const fn name(self) -> &'static str {
match self {
Lang::Rust => "rust",
Lang::Python => "python",
Lang::JavaScript => "javascript",
Lang::TypeScript => "typescript",
Lang::Tsx => "tsx",
Lang::Go => "go",
Lang::Java => "java",
}
}
fn language(self) -> tree_sitter::Language {
match self {
Lang::Rust => tree_sitter_rust::LANGUAGE.into(),
Lang::Python => tree_sitter_python::LANGUAGE.into(),
Lang::JavaScript => tree_sitter_javascript::LANGUAGE.into(),
Lang::TypeScript => tree_sitter_typescript::LANGUAGE_TYPESCRIPT.into(),
Lang::Tsx => tree_sitter_typescript::LANGUAGE_TSX.into(),
Lang::Go => tree_sitter_go::LANGUAGE.into(),
Lang::Java => tree_sitter_java::LANGUAGE.into(),
}
}
const fn tags_query(self) -> &'static str {
match self {
Lang::Rust => tree_sitter_rust::TAGS_QUERY,
Lang::Python => tree_sitter_python::TAGS_QUERY,
Lang::JavaScript => tree_sitter_javascript::TAGS_QUERY,
Lang::TypeScript | Lang::Tsx => tree_sitter_typescript::TAGS_QUERY,
Lang::Go => tree_sitter_go::TAGS_QUERY,
Lang::Java => tree_sitter_java::TAGS_QUERY,
}
}
const fn all() -> [Lang; 7] {
[
Lang::Rust,
Lang::Python,
Lang::JavaScript,
Lang::TypeScript,
Lang::Tsx,
Lang::Go,
Lang::Java,
]
}
}
pub fn detect(path: &Path) -> Option<Lang> {
let ext = path.extension()?.to_str()?.to_ascii_lowercase();
Some(match ext.as_str() {
"rs" => Lang::Rust,
"py" | "pyi" => Lang::Python,
"js" | "jsx" | "mjs" | "cjs" => Lang::JavaScript,
"ts" | "mts" | "cts" => Lang::TypeScript,
"tsx" => Lang::Tsx,
"go" => Lang::Go,
"java" => Lang::Java,
_ => return None,
})
}
fn configs() -> &'static HashMap<Lang, TagsConfiguration> {
static CONFIGS: OnceLock<HashMap<Lang, TagsConfiguration>> = OnceLock::new();
CONFIGS.get_or_init(|| {
let mut m = HashMap::new();
for lang in Lang::all() {
match TagsConfiguration::new(lang.language(), lang.tags_query(), "") {
Ok(cfg) => {
m.insert(lang, cfg);
}
Err(e) => {
tracing::warn!("code: tags config for {} failed: {e}", lang.name());
}
}
}
m
})
}
pub fn config(lang: Lang) -> Option<&'static TagsConfiguration> {
configs().get(&lang)
}