use std::env;
use std::path::PathBuf;
use crate::util::app_info::APP_NAME;
pub fn home_dir() -> Option<PathBuf> {
if let Ok(home) = env::var("HOME")
&& !home.is_empty()
{
return Some(PathBuf::from(home));
}
if let Ok(profile) = env::var("USERPROFILE")
&& !profile.is_empty()
{
return Some(PathBuf::from(profile));
}
match (env::var("HOMEDRIVE"), env::var("HOMEPATH")) {
(Ok(drive), Ok(path)) if !drive.is_empty() && !path.is_empty() => {
Some(PathBuf::from(format!("{drive}{path}")))
}
_ => None,
}
}
pub fn expand_tilde(path: &str) -> PathBuf {
if path == "~" {
return home_dir().unwrap_or_else(|| PathBuf::from(path));
}
if let Some(rest) = path.strip_prefix("~/")
&& let Some(home) = home_dir()
{
return home.join(rest);
}
PathBuf::from(path)
}
fn xdg_dir(env_var: &str, fallback: &str) -> PathBuf {
if let Ok(base) = env::var(env_var)
&& !base.is_empty()
{
return PathBuf::from(base).join(APP_NAME);
}
let home = home_dir().unwrap_or_else(|| PathBuf::from("."));
home.join(fallback).join(APP_NAME)
}
#[cfg(windows)]
fn windows_dir(env_var: &str) -> Option<PathBuf> {
env::var(env_var)
.ok()
.filter(|base| !base.is_empty())
.map(|base| PathBuf::from(base).join(APP_NAME))
}
pub fn config_dir() -> PathBuf {
#[cfg(windows)]
if let Some(dir) = windows_dir("APPDATA") {
return dir;
}
xdg_dir("XDG_CONFIG_HOME", ".config")
}
pub fn state_dir() -> PathBuf {
#[cfg(windows)]
if let Some(dir) = windows_dir("LOCALAPPDATA") {
return dir;
}
xdg_dir("XDG_STATE_HOME", ".local/state")
}
pub fn config_file() -> PathBuf {
config_dir().join("config.toml")
}
pub fn cache_file() -> PathBuf {
state_dir().join("git-info-cache.toml")
}
pub fn usage_file() -> PathBuf {
state_dir().join("usage.toml")
}
pub fn selected_repo_file() -> PathBuf {
state_dir().join("selected-repo.txt")
}
pub fn log_file() -> PathBuf {
state_dir().join("hop.log")
}
pub fn ui_state_file() -> PathBuf {
state_dir().join("ui-state.toml")
}
pub fn stats_file() -> PathBuf {
state_dir().join("stats-cache.toml")
}