use std::borrow::Cow;
use std::collections::HashMap;
use std::sync::Mutex;
use std::sync::OnceLock;
static CATALOG: OnceLock<Mutex<HashMap<String, String>>> = OnceLock::new();
type InterceptorFn = dyn Fn(&str, &str) -> Cow<'static, str> + Send + Sync;
static INTERCEPTOR: OnceLock<Mutex<Option<Box<InterceptorFn>>>> = OnceLock::new();
fn catalog() -> &'static Mutex<HashMap<String, String>> {
CATALOG.get_or_init(|| Mutex::new(HashMap::new()))
}
fn interceptor() -> &'static Mutex<Option<Box<InterceptorFn>>> {
INTERCEPTOR.get_or_init(|| Mutex::new(None))
}
pub fn set_message<K: Into<String>, V: Into<String>>(key: K, value: V) {
if let Ok(mut map) = catalog().lock() {
map.insert(key.into(), value.into());
}
}
pub fn reset_message(key: &str) {
if let Ok(mut map) = catalog().lock() {
map.remove(key);
}
}
pub fn get_message(key: &str) -> Option<String> {
catalog().lock().ok().and_then(|m| m.get(key).cloned())
}
pub fn message_or_default<'a>(key: &str, default: &'a str) -> Cow<'a, str> {
if let Some(val) = get_message(key) {
Cow::Owned(val)
} else {
Cow::Borrowed(default)
}
}
pub fn set_output_interceptor<F>(f: F)
where
F: Fn(&str, &str) -> Cow<'static, str> + Send + Sync + 'static,
{
if let Ok(mut slot) = interceptor().lock() {
*slot = Some(Box::new(f));
}
}
pub fn clear_output_interceptor() {
if let Ok(mut slot) = interceptor().lock() {
*slot = None;
}
}
pub fn intercept<'a>(category: &str, text: &'a str) -> Cow<'a, str> {
if let Ok(slot) = interceptor().lock() {
if let Some(ref cb) = *slot {
let owned: Cow<'static, str> = cb(category, text);
return Cow::Owned(owned.into_owned());
}
}
Cow::Borrowed(text)
}
#[cfg(feature = "theme-config")]
pub fn load_messages_from_json(path: &str) -> Result<(), crate::error::ModCliError> {
let data = std::fs::read_to_string(path)?;
let map: HashMap<String, String> = serde_json::from_str(&data)?;
if let Ok(mut cat) = catalog().lock() {
for (k, v) in map {
cat.insert(k, v);
}
}
Ok(())
}
#[cfg(not(feature = "theme-config"))]
pub fn load_messages_from_json(_path: &str) -> Result<(), crate::error::ModCliError> {
Err(crate::error::ModCliError::InvalidUsage(
"messages JSON loader requires feature: theme-config".into(),
))
}