use std::ffi::OsString;
use std::path::{Path, PathBuf};
const SESSION_FILE: &str = "last-session.nm";
pub fn home_dir() -> Option<PathBuf> {
std::env::home_dir().filter(|p| !p.as_os_str().is_empty())
}
pub fn session_path() -> Option<PathBuf> {
session_path_from(std::env::var_os("XDG_DATA_HOME"), home_dir())
}
pub fn session_path_from(
xdg_data_home: Option<OsString>,
home: Option<PathBuf>,
) -> Option<PathBuf> {
let data_dir = xdg_data_home
.map(PathBuf::from)
.filter(|p| p.is_absolute())
.or_else(|| home.map(|h| h.join(".local").join("share")))?;
Some(data_dir.join("nm").join(SESSION_FILE))
}
pub fn expand_tilde(path: &Path) -> PathBuf {
expand_tilde_with(path, home_dir().as_deref())
}
pub fn expand_tilde_with(path: &Path, home: Option<&Path>) -> PathBuf {
if let Some(home) = home
&& let Ok(rest) = path.strip_prefix("~")
&& path.as_os_str().len() > 1
{
return home.join(rest);
}
path.to_path_buf()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_session_path() {
let path = session_path_from(None, Some(PathBuf::from("/home/u"))).unwrap();
assert!(path.ends_with(SESSION_FILE));
assert!(path.ends_with(Path::new(".local/share/nm/last-session.nm")));
assert_eq!(path, Path::new("/home/u/.local/share/nm/last-session.nm"));
}
#[test]
fn session_path_from_real_environment() {
if let Some(path) = session_path() {
assert!(path.ends_with(Path::new("nm/last-session.nm")));
}
}
#[test]
fn session_path_honours_xdg_data_home() {
let path = session_path_from(Some("/xdg/data".into()), Some(PathBuf::from("/home/u")));
assert_eq!(path.unwrap(), Path::new("/xdg/data/nm/last-session.nm"));
}
#[test]
fn session_path_ignores_empty_or_relative_xdg() {
for xdg in ["", "relative/data"] {
let path = session_path_from(Some(xdg.into()), Some(PathBuf::from("/home/u")));
assert_eq!(
path.unwrap(),
Path::new("/home/u/.local/share/nm/last-session.nm"),
"XDG_DATA_HOME={xdg:?}"
);
}
}
#[test]
fn session_path_without_home_or_xdg() {
assert_eq!(session_path_from(None, None), None);
assert_eq!(
session_path_from(Some("/x".into()), None).unwrap(),
Path::new("/x/nm/last-session.nm")
);
}
#[test]
fn expand_tilde_cases() {
let home = Some(Path::new("/home/u"));
let cases = [
("~/notes/a.nm", "/home/u/notes/a.nm"),
("~/", "/home/u"),
("~", "~"),
("~user/a.nm", "~user/a.nm"),
("/abs/a.nm", "/abs/a.nm"),
("rel/~/a.nm", "rel/~/a.nm"),
("a.nm", "a.nm"),
];
for (input, want) in cases {
assert_eq!(
expand_tilde_with(Path::new(input), home),
Path::new(want),
"{input}"
);
}
}
#[test]
fn expand_tilde_without_home() {
assert_eq!(
expand_tilde_with(Path::new("~/a.nm"), None),
Path::new("~/a.nm")
);
}
}