gravel_ffi/
paths.rs

1//! Defines useful functions for working with common paths.
2
3use std::{env, iter::once, path::PathBuf};
4
5const XDG_DATA_HOME: &str = "XDG_DATA_HOME";
6const XDG_DATA_DIRS: &str = "XDG_DATA_DIRS";
7
8/// Returns the user's home directory.
9///
10/// # Panics
11/// When `$HOME/$USERPROFILE` are not set.
12pub fn home() -> PathBuf {
13	#[cfg(unix)]
14	let home = env::var("HOME").expect("$HOME must always be set");
15
16	#[cfg(windows)]
17	let home = env::var("USERPROFILE").expect("$USERPROFILE must always be set");
18
19	PathBuf::from(home)
20}
21
22/// Returns the value of `$XDG_CONFIG_HOME` or the default value.
23pub fn xdg_config_home() -> PathBuf {
24	if let Ok(path) = env::var("XDG_CONFIG_HOME") {
25		return path.into();
26	}
27
28	home().join(".config")
29}
30
31/// Returns the value of `$XDG_DATA_HOME` or the default value.
32pub fn xdg_data_home() -> PathBuf {
33	if let Ok(path) = env::var(XDG_DATA_HOME) {
34		return path.into();
35	}
36
37	home().join(".local/share")
38}
39
40/// Returns the value of `$XDG_DATA_DIRS` or the default value.
41pub fn xdg_data_dirs() -> Vec<PathBuf> {
42	if let Ok(path) = env::var(XDG_DATA_DIRS) {
43		return path.split(':').map(PathBuf::from).collect();
44	}
45
46	#[cfg(unix)]
47	return vec![PathBuf::from("/usr/local/share/"), PathBuf::from("/usr/share/")];
48
49	#[cfg(windows)]
50	return vec![];
51}
52
53/// Returns [`xdg_data_home`] plus [`xdg_data_dirs`], postfixed with `path`.
54pub fn xdg_data_globs(path: &str) -> impl Iterator<Item = PathBuf> + '_ {
55	once(xdg_data_home()).chain(xdg_data_dirs()).map(move |mut p| {
56		p.push(path);
57		p
58	})
59}
60
61/// Returns the value of `$XDG_STATE_HOME` or the default value.
62pub fn xdg_state_home() -> PathBuf {
63	if let Ok(path) = env::var("XDG_STATE_HOME") {
64		return path.into();
65	}
66
67	home().join(".local/state")
68}
69
70#[cfg(test)]
71mod tests {
72	use super::*;
73	use rstest::rstest;
74
75	#[rstest]
76	pub fn should_return_globs() {
77		unsafe {
78			// this is fine for now because there's only one test that deals with env vars
79			env::set_var(XDG_DATA_HOME, "/home/user/.xdg/share");
80			env::set_var(XDG_DATA_DIRS, "/share:/data");
81		}
82
83		let paths = xdg_data_globs("test/*").collect::<Vec<_>>();
84
85		assert_eq!(
86			paths,
87			vec![
88				PathBuf::from("/home/user/.xdg/share/test/*"),
89				PathBuf::from("/share/test/*"),
90				PathBuf::from("/data/test/*")
91			]
92		);
93	}
94}