use directories::ProjectDirs;
use std::path::PathBuf;
use std::sync::LazyLock;
use std::{env, fs, io};
use tectonic_errors::prelude::*;
pub use directories;
static PROJECT_DIRS: LazyLock<Option<ProjectDirs>> =
LazyLock::new(|| ProjectDirs::from("", "TectonicProject", "Tectonic"));
fn dirs() -> Result<&'static ProjectDirs> {
PROJECT_DIRS.as_ref().ok_or_else(|| {
Error::from(io::Error::new(
io::ErrorKind::NotFound,
"Unable to find standard directories for platform",
))
})
}
pub fn get_user_config() -> Result<PathBuf> {
Ok(dirs()?.config_dir().to_path_buf())
}
pub fn ensure_user_config() -> Result<PathBuf> {
let path = get_user_config()?;
fs::create_dir_all(&path)?;
Ok(path)
}
pub fn get_user_cache_dir(subdir: &str) -> Result<PathBuf> {
let env_cache_path = env::var_os("TECTONIC_CACHE_DIR");
let cache_path = match env_cache_path {
Some(env_cache_path) => {
let mut env_cache_path: PathBuf = env_cache_path.into();
env_cache_path.push(subdir);
fs::create_dir_all(&env_cache_path)?;
env_cache_path
}
None => dirs()?.cache_dir().join(subdir),
};
Ok(cache_path)
}
pub fn sanitize(component: &str) -> String {
let mut buf = String::with_capacity(component.len());
for (i, c) in component.chars().enumerate() {
let is_alnum = c.is_ascii_alphanumeric();
let is_space = c == ' ';
let is_hyphen = c == '-';
let is_underscore = c == '_';
let is_period = c == '.' && i != 0; let is_valid = is_alnum || is_space || is_hyphen || is_underscore || is_period;
if is_valid {
buf.push(c);
} else {
use std::fmt::Write;
let _ = write!(&mut buf, ",{},", c as u32);
}
}
buf
}