use std::path::PathBuf;
pub fn get_config_dir() -> PathBuf {
if let Some(custom) = std::env::var_os("TOKMESH_CONFIG_DIR") {
if !custom.is_empty() {
return PathBuf::from(custom);
}
}
#[cfg(target_os = "macos")]
{
if let Some(home) = dirs::home_dir() {
return home.join(".config").join("tokmesh");
}
}
dirs::config_dir()
.map(|d| d.join("tokmesh"))
.unwrap_or_else(|| PathBuf::from(".tokmesh"))
}
pub fn get_cache_dir() -> PathBuf {
get_config_dir().join("cache")
}
pub fn is_config_dir_overridden() -> bool {
std::env::var_os("TOKMESH_CONFIG_DIR").is_some_and(|v| !v.is_empty())
}
#[cfg(test)]
mod tests {
use super::*;
use serial_test::serial;
use std::env;
use std::path::Path;
fn save_env() -> (
Option<std::ffi::OsString>,
Option<std::ffi::OsString>,
Option<std::ffi::OsString>,
) {
(
env::var_os("TOKMESH_CONFIG_DIR"),
env::var_os("HOME"),
env::var_os("XDG_CONFIG_HOME"),
)
}
fn restore_env(
prev: (
Option<std::ffi::OsString>,
Option<std::ffi::OsString>,
Option<std::ffi::OsString>,
),
) {
unsafe {
match prev.0 {
Some(v) => env::set_var("TOKMESH_CONFIG_DIR", v),
None => env::remove_var("TOKMESH_CONFIG_DIR"),
}
match prev.1 {
Some(v) => env::set_var("HOME", v),
None => env::remove_var("HOME"),
}
match prev.2 {
Some(v) => env::set_var("XDG_CONFIG_HOME", v),
None => env::remove_var("XDG_CONFIG_HOME"),
}
}
}
#[test]
#[serial]
fn env_override_is_returned_verbatim() {
let prev = save_env();
unsafe {
env::set_var("TOKMESH_CONFIG_DIR", "/tmp/tokmesh-custom");
}
assert_eq!(get_config_dir(), PathBuf::from("/tmp/tokmesh-custom"));
restore_env(prev);
}
#[test]
#[serial]
#[cfg(any(target_os = "macos", target_os = "linux"))]
fn unix_default_is_dot_config_tokmesh_under_home() {
let prev = save_env();
unsafe {
env::remove_var("TOKMESH_CONFIG_DIR");
env::remove_var("XDG_CONFIG_HOME");
env::set_var("HOME", "/tmp/tokmesh-core-paths-home");
}
assert_eq!(
get_config_dir(),
PathBuf::from("/tmp/tokmesh-core-paths-home/.config/tokmesh"),
);
restore_env(prev);
}
#[test]
#[serial]
#[cfg(target_os = "linux")]
fn linux_honors_xdg_config_home_when_set() {
let prev = save_env();
unsafe {
env::remove_var("TOKMESH_CONFIG_DIR");
env::set_var("XDG_CONFIG_HOME", "/tmp/tokmesh-core-paths-xdg");
}
assert_eq!(
get_config_dir(),
PathBuf::from("/tmp/tokmesh-core-paths-xdg/tokmesh"),
);
restore_env(prev);
}
#[test]
#[serial]
fn cache_dir_is_cache_subdir_of_config_dir() {
let prev = save_env();
unsafe {
env::set_var("TOKMESH_CONFIG_DIR", "/tmp/tokmesh-cache-test");
}
assert_eq!(
get_cache_dir(),
PathBuf::from("/tmp/tokmesh-cache-test/cache")
);
restore_env(prev);
}
#[test]
#[serial]
fn get_config_dir_treats_empty_override_as_unset() {
let prev = save_env();
unsafe {
env::set_var("TOKMESH_CONFIG_DIR", "");
}
let resolved = get_config_dir();
assert_ne!(
resolved,
PathBuf::from(""),
"empty override must not resolve to the empty path"
);
assert!(
resolved.is_absolute() || resolved == Path::new(".tokmesh"),
"empty override must fall through to platform default, got {resolved:?}"
);
restore_env(prev);
}
#[test]
#[serial]
fn is_config_dir_overridden_treats_empty_string_as_unset() {
let prev = save_env();
unsafe {
env::set_var("TOKMESH_CONFIG_DIR", "");
}
assert!(!is_config_dir_overridden());
restore_env(prev);
}
}