use std::path::PathBuf;
use include_dir::{include_dir, Dir};
use crate::error::{Error, Result};
static DATA_DIR: Dir<'static> = include_dir!("$CARGO_MANIFEST_DIR/data");
#[derive(Clone, Debug, Default)]
pub enum DataSource {
#[default]
Embedded,
Filesystem {
patterns_dir: PathBuf,
languages_dir: PathBuf,
},
}
#[derive(Clone, Debug, Default)]
pub struct Config {
pub source: DataSource,
}
impl Config {
pub fn default_embedded() -> Self {
Config {
source: DataSource::Embedded,
}
}
pub fn from_dirs(patterns_dir: impl Into<PathBuf>, languages_dir: impl Into<PathBuf>) -> Self {
Config {
source: DataSource::Filesystem {
patterns_dir: patterns_dir.into(),
languages_dir: languages_dir.into(),
},
}
}
pub(crate) fn read_language(&self, code: &str) -> Result<Option<String>> {
let name = format!("{code}.json");
match &self.source {
DataSource::Embedded => Ok(DATA_DIR
.get_file(format!("languages/{name}"))
.and_then(|f| f.contents_utf8())
.map(|s| s.to_string())),
DataSource::Filesystem { languages_dir, .. } => {
let path = languages_dir.join(&name);
if path.exists() {
Ok(Some(std::fs::read_to_string(path)?))
} else {
Ok(None)
}
}
}
}
pub(crate) fn read_pattern(&self, code: &str) -> Result<String> {
let name = format!("hyph-{code}.tex");
match &self.source {
DataSource::Embedded => DATA_DIR
.get_file(format!("patterns/{name}"))
.and_then(|f| f.contents_utf8())
.map(|s| s.to_string())
.ok_or(Error::PatternFileNotFound(name)),
DataSource::Filesystem { patterns_dir, .. } => {
let path = patterns_dir.join(&name);
if path.exists() {
Ok(std::fs::read_to_string(path)?)
} else {
Err(Error::PatternFileNotFound(path.display().to_string()))
}
}
}
}
pub(crate) fn list_language_codes(&self) -> Result<Vec<String>> {
let mut codes: Vec<String> = match &self.source {
DataSource::Embedded => DATA_DIR
.get_dir("languages")
.map(|d| {
d.files()
.filter_map(|f| {
let p = f.path();
(p.extension().and_then(|e| e.to_str()) == Some("json"))
.then(|| p.file_stem().and_then(|s| s.to_str()).map(String::from))
.flatten()
})
.collect()
})
.unwrap_or_default(),
DataSource::Filesystem { languages_dir, .. } => {
let mut v = Vec::new();
if let Ok(entries) = std::fs::read_dir(languages_dir) {
for entry in entries.flatten() {
let p = entry.path();
if p.extension().and_then(|e| e.to_str()) == Some("json") {
if let Some(stem) = p.file_stem().and_then(|s| s.to_str()) {
v.push(stem.to_string());
}
}
}
}
v
}
};
codes.sort();
Ok(codes)
}
}