thoughts_tool/utils/
paths.rs1use anyhow::Result;
2use dirs;
3use std::path::{Path, PathBuf};
4
5pub fn expand_path(path: &Path) -> Result<PathBuf> {
7 let path_str = path.to_string_lossy();
8
9 if let Some(stripped) = path_str.strip_prefix("~/") {
10 let home = dirs::home_dir()
11 .ok_or_else(|| anyhow::anyhow!("Could not determine home directory"))?;
12 Ok(home.join(stripped))
13 } else if path_str == "~" {
14 dirs::home_dir().ok_or_else(|| anyhow::anyhow!("Could not determine home directory"))
15 } else {
16 Ok(path.to_path_buf())
17 }
18}
19
20pub fn ensure_dir(path: &Path) -> Result<()> {
22 if !path.exists() {
23 std::fs::create_dir_all(path)?;
24 }
25 Ok(())
26}
27
28pub fn sanitize_dir_name(name: &str) -> String {
30 name.chars()
31 .map(|c| match c {
32 '/' | '\\' | ':' | '*' | '?' | '"' | '<' | '>' | '|' => '_',
33 _ => c,
34 })
35 .collect()
36}
37
38pub fn get_repo_config_path(repo_root: &Path) -> PathBuf {
42 repo_root.join(".thoughts").join("config.json")
43}
44
45#[cfg(target_os = "macos")]
47pub fn get_external_metadata_dir() -> Result<PathBuf> {
48 let home =
49 dirs::home_dir().ok_or_else(|| anyhow::anyhow!("Could not determine home directory"))?;
50 Ok(home.join(".thoughts").join("data").join("external"))
51}
52
53#[allow(dead_code)]
55pub fn get_local_metadata_path(repo_root: &Path) -> PathBuf {
57 repo_root.join(".thoughts").join("data").join("local.json")
58}
59
60#[allow(dead_code)]
62pub fn get_repo_rules_path(repo_root: &Path) -> PathBuf {
64 repo_root.join(".thoughts").join("rules.json")
65}
66
67pub fn get_repo_mapping_path() -> Result<PathBuf> {
69 let home =
70 dirs::home_dir().ok_or_else(|| anyhow::anyhow!("Could not determine home directory"))?;
71 Ok(home.join(".thoughts").join("repos.json"))
72}
73
74pub fn get_personal_config_path() -> Result<PathBuf> {
76 let home =
77 dirs::home_dir().ok_or_else(|| anyhow::anyhow!("Could not determine home directory"))?;
78 Ok(home.join(".thoughts").join("config.json"))
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84 use serial_test::serial;
85
86 #[test]
87 #[serial]
88 fn test_expand_path() {
89 let home = dirs::home_dir().unwrap();
91 assert_eq!(expand_path(Path::new("~/test")).unwrap(), home.join("test"));
92 assert_eq!(expand_path(Path::new("~")).unwrap(), home);
93
94 assert_eq!(
96 expand_path(Path::new("/tmp/test")).unwrap(),
97 PathBuf::from("/tmp/test")
98 );
99
100 assert_eq!(
102 expand_path(Path::new("test")).unwrap(),
103 PathBuf::from("test")
104 );
105 }
106
107 #[test]
108 fn test_sanitize_dir_name() {
109 assert_eq!(sanitize_dir_name("normal-name_123"), "normal-name_123");
110 assert_eq!(
111 sanitize_dir_name("bad/name:with*chars?"),
112 "bad_name_with_chars_"
113 );
114 }
115}