1use std::{
2 fs::canonicalize,
3 path::{Path, PathBuf},
4};
5
6const STORAGE_PATH: &str = ".local/share/odds/";
7
8pub fn detect_explicit_path(input: &str) -> Option<PathBuf> {
9 let path = Path::new(input);
10 if path.exists() && path.is_dir() {
11 Some(path.to_path_buf())
12 } else {
13 None
14 }
15}
16pub fn search_roots() -> Vec<PathBuf> {
20 let mut roots = Vec::new();
21
22 if let Ok(pwd) = std::env::current_dir() {
23 roots.push(pwd.clone());
24
25 if let Some(git_root) = find_git_root(&pwd) {
26 if git_root != pwd {
27 roots.push(git_root);
28 }
29 }
30 }
31
32 if let Ok(home) = std::env::var("HOME") {
33 roots.push(PathBuf::from(home));
34 }
35
36 roots.sort();
37 roots.dedup();
38
39 roots
40}
41
42pub fn normalize<P: AsRef<Path>>(path: P) -> PathBuf {
43 let p = path.as_ref();
44
45 canonicalize(p).unwrap_or_else(|_| p.to_path_buf())
46}
47
48pub fn persistence_path(file: &str) -> PathBuf {
51 home_dir().join(STORAGE_PATH).join(file)
52}
53
54pub fn home_dir() -> PathBuf {
55 std::env::var("HOME")
56 .map(PathBuf::from)
57 .unwrap_or_else(|_| {
58 eprintln!("Warning: $HOME is not set, falling back to current directory.");
59 PathBuf::from(".")
60 })
61}
62
63fn find_git_root(start: &Path) -> Option<PathBuf> {
64 let mut current = Some(start);
65
66 while let Some(dir) = current {
67 if dir.join(".git").exists() {
68 return Some(dir.to_path_buf());
69 }
70 current = dir.parent();
71 }
72
73 None
74}