Skip to main content

codei_config/
paths.rs

1use std::env;
2use std::path::{Path, PathBuf};
3
4use directories::ProjectDirs;
5
6const APP_QUALIFIER: &str = "com";
7const APP_ORG: &str = "codei";
8const APP_NAME: &str = "codei";
9
10/// Returns the user-level configuration directory (`~/.config/codei` on Linux).
11pub fn user_config_dir() -> PathBuf {
12    ProjectDirs::from(APP_QUALIFIER, APP_ORG, APP_NAME)
13        .map(|dirs| dirs.config_dir().to_path_buf())
14        .unwrap_or_else(|| PathBuf::from(".config/codei"))
15}
16
17/// Returns the directory for debug/runtime logs (`~/.local/share/codei/logs` on Linux).
18pub fn user_log_dir() -> PathBuf {
19    ProjectDirs::from(APP_QUALIFIER, APP_ORG, APP_NAME)
20        .map(|dirs| dirs.data_local_dir().join("logs"))
21        .unwrap_or_else(|| PathBuf::from(".local/share/codei/logs"))
22}
23
24/// Path to the append-only debug log file used with `codei --verbose`.
25pub fn debug_log_path() -> PathBuf {
26    user_log_dir().join("debug.log")
27}
28
29/// Returns the path to the user-level config file.
30pub fn user_config_path() -> PathBuf {
31    user_config_dir().join("config.toml")
32}
33
34/// Returns the project-level config path under `.codei/config.toml`.
35pub fn project_config_path(project_root: &Path) -> PathBuf {
36    project_root.join(".codei").join("config.toml")
37}
38
39/// Walks up from `start` looking for project markers.
40pub fn discover_project_root(start: &Path) -> Option<PathBuf> {
41    let start = start.canonicalize().ok()?;
42    let mut current = start;
43
44    loop {
45        if is_project_root(&current) {
46            return Some(current);
47        }
48        if !current.pop() {
49            break;
50        }
51    }
52
53    None
54}
55
56fn is_project_root(path: &Path) -> bool {
57    path.join(".git").exists() || path.join(".codei").is_dir() || path.join("AGENTS.md").is_file()
58}
59
60/// Expands a leading `~` using `HOME`.
61pub fn expand_tilde(path: &str) -> PathBuf {
62    if let Some(rest) = path.strip_prefix("~/") {
63        if let Ok(home) = env::var("HOME") {
64            return PathBuf::from(home).join(rest);
65        }
66    }
67    PathBuf::from(path)
68}
69
70#[cfg(test)]
71mod tests {
72    use super::*;
73
74    #[test]
75    fn expand_tilde_uses_home() {
76        if let Ok(home) = env::var("HOME") {
77            assert_eq!(
78                expand_tilde("~/sessions"),
79                PathBuf::from(home).join("sessions")
80            );
81        }
82    }
83}