use std::collections::HashMap;
use super::LanguagePack;
pub type ContentProbe = fn(content: &[u8]) -> bool;
pub struct LanguageRegistry {
by_extension: HashMap<String, usize>,
packs: Vec<LanguagePack>,
content_overrides: HashMap<String, (usize, ContentProbe)>,
}
impl LanguageRegistry {
pub fn new() -> Self {
Self {
by_extension: HashMap::new(),
packs: Vec::new(),
content_overrides: HashMap::new(),
}
}
pub fn register(&mut self, pack: LanguagePack) {
let idx = self.packs.len();
for ext in &pack.extensions {
self.by_extension.insert(ext.clone(), idx);
}
self.packs.push(pack);
}
pub fn register_with_content_probe(
&mut self,
pack: LanguagePack,
probe_extensions: &[&str],
probe: ContentProbe,
) {
let idx = self.packs.len();
for ext in &pack.extensions {
self.by_extension.insert(ext.clone(), idx);
}
for ext in probe_extensions {
self.content_overrides.insert(ext.to_string(), (idx, probe));
}
self.packs.push(pack);
}
pub fn for_extension(&self, ext: &str) -> Option<&LanguagePack> {
self.by_extension.get(ext).map(|&idx| &self.packs[idx])
}
pub fn for_file(&self, path: &str) -> Option<&LanguagePack> {
let ext = path.rsplit_once('.').map(|(_, e)| format!(".{e}"))?;
self.for_extension(&ext)
}
pub fn for_file_with_content(&self, path: &str, content: &[u8]) -> Option<&LanguagePack> {
let ext = path.rsplit_once('.').map(|(_, e)| format!(".{e}"))?;
if let Some(&(idx, probe)) = self.content_overrides.get(&ext) {
if probe(content) {
return Some(&self.packs[idx]);
}
}
self.for_extension(&ext)
}
pub fn languages(&self) -> impl Iterator<Item = &LanguagePack> {
self.packs.iter()
}
}
impl Default for LanguageRegistry {
fn default() -> Self {
Self::new()
}
}