oxur_cli/config/
paths.rs

1//! Path resolution for REPL configuration
2//!
3//! Provides XDG-compliant path resolution with fallbacks for config,
4//! data, and cache directories.
5
6use std::path::PathBuf;
7
8/// Find the REPL config file with XDG fallback
9///
10/// Searches in order:
11/// 1. `$XDG_CONFIG_HOME/oxur/repl.toml` (if XDG_CONFIG_HOME set)
12/// 2. `~/.config/oxur/repl.toml` (XDG default)
13/// 3. `~/.oxur/repl.toml` (fallback)
14///
15/// Returns None if no config file exists.
16pub fn find_config_file() -> Option<PathBuf> {
17    // Check custom path from environment
18    if let Ok(custom) = std::env::var("OXUR_CONFIG_PATH") {
19        let path = PathBuf::from(custom);
20        if path.exists() {
21            return Some(path);
22        }
23    }
24
25    // Try XDG config directory
26    if let Some(config_dir) = dirs::config_dir() {
27        let path = config_dir.join("oxur").join("repl.toml");
28        if path.exists() {
29            return Some(path);
30        }
31    }
32
33    // Fallback to ~/.oxur/repl.toml
34    if let Some(home) = dirs::home_dir() {
35        let path = home.join(".oxur").join("repl.toml");
36        if path.exists() {
37            return Some(path);
38        }
39    }
40
41    None
42}
43
44/// Get the default history file path
45///
46/// Uses XDG data directory or falls back to ~/.local/share/oxur/repl_history
47pub fn default_history_path() -> PathBuf {
48    // Check custom path from environment
49    if let Ok(custom) = std::env::var("OXUR_HISTORY_PATH") {
50        return PathBuf::from(custom);
51    }
52
53    // Use XDG data directory
54    dirs::data_dir().unwrap_or_else(|| PathBuf::from(".")).join("oxur").join("repl_history")
55}
56
57/// Get the default config directory
58///
59/// Returns XDG config directory or ~/.config/oxur
60pub fn config_dir() -> PathBuf {
61    dirs::config_dir().unwrap_or_else(|| PathBuf::from(".")).join("oxur")
62}
63
64/// Get the default data directory
65///
66/// Returns XDG data directory or ~/.local/share/oxur
67pub fn data_dir() -> PathBuf {
68    dirs::data_dir().unwrap_or_else(|| PathBuf::from(".")).join("oxur")
69}
70
71/// Get the default cache directory
72///
73/// Returns XDG cache directory or ~/.cache/oxur
74pub fn cache_dir() -> PathBuf {
75    dirs::cache_dir().unwrap_or_else(|| PathBuf::from(".")).join("oxur")
76}
77
78#[cfg(test)]
79mod tests {
80    use super::*;
81
82    #[test]
83    fn test_default_history_path_contains_oxur() {
84        let path = default_history_path();
85        assert!(path.to_string_lossy().contains("oxur"));
86        assert!(path.to_string_lossy().contains("repl_history"));
87    }
88
89    #[test]
90    fn test_config_dir_contains_oxur() {
91        let path = config_dir();
92        assert!(path.ends_with("oxur"));
93    }
94
95    #[test]
96    fn test_data_dir_contains_oxur() {
97        let path = data_dir();
98        assert!(path.ends_with("oxur"));
99    }
100
101    #[test]
102    fn test_cache_dir_contains_oxur() {
103        let path = cache_dir();
104        assert!(path.ends_with("oxur"));
105    }
106
107    #[test]
108    fn test_find_config_file_returns_none_when_no_file() {
109        // This test may pass or fail depending on whether the user has a config file
110        // It's mainly here to verify the function doesn't panic
111        let _ = find_config_file();
112    }
113}