navi

Obsidian-style interactive graph viewer for org-roam — native window, no Emacs package required.
Log | Files | Refs | README

config.rs (2979B)


      1 use serde::{Deserialize, Serialize};
      2 use std::path::PathBuf;
      3 
      4 #[derive(Debug, Clone, Serialize, Deserialize)]
      5 pub struct Config {
      6     #[serde(default)]
      7     pub db: String,
      8     #[serde(default)]
      9     pub emacsclient: String,
     10     #[serde(default = "default_server")]
     11     pub server_name: String,
     12     #[serde(default = "default_true")]
     13     pub show_fps: bool,
     14     #[serde(default)]
     15     pub borderless: bool,
     16 }
     17 
     18 fn default_server() -> String { "server".into() }
     19 fn default_true() -> bool { true }
     20 
     21 impl Default for Config {
     22     fn default() -> Self {
     23         Config {
     24             db: String::new(),
     25             emacsclient: String::new(),
     26             server_name: "server".into(),
     27             show_fps: true,
     28             borderless: false,
     29         }
     30     }
     31 }
     32 
     33 impl Config {
     34     pub fn config_path() -> PathBuf {
     35         dirs::home_dir()
     36             .unwrap_or_default()
     37             .join(".config")
     38             .join("navi")
     39             .join("config.json")
     40     }
     41 
     42     pub fn load() -> Self {
     43         let path = Self::config_path();
     44         if path.exists() {
     45             if let Ok(s) = std::fs::read_to_string(&path) {
     46                 if let Ok(c) = serde_json::from_str(&s) {
     47                     return c;
     48                 }
     49             }
     50         }
     51         Config::default()
     52     }
     53 
     54     pub fn save(&self) {
     55         let path = Self::config_path();
     56         if let Some(parent) = path.parent() {
     57             let _ = std::fs::create_dir_all(parent);
     58         }
     59         if let Ok(s) = serde_json::to_string_pretty(self) {
     60             let _ = std::fs::write(&path, s);
     61         }
     62     }
     63 }
     64 
     65 // ── DB path detection ─────────────────────────────────────────────────────────
     66 
     67 static DB_CANDIDATES: &[&str] = &[
     68     "~/.emacs.d/org-roam.db",
     69     "~/.config/emacs/org-roam.db",
     70     "~/.config/doom/.local/etc/org-roam.db",
     71     "~/.config/doom/org-roam.db",
     72     "~/.doom.d/.local/etc/org-roam.db",
     73     "~/.doom.d/org-roam.db",
     74     "~/.spacemacs.d/org-roam.db",
     75 ];
     76 
     77 pub fn detect_db() -> String {
     78     if let Ok(v) = std::env::var("ORG_ROAM_DB") {
     79         if std::path::Path::new(&v).exists() {
     80             return v;
     81         }
     82     }
     83     // XDG_DATA_HOME
     84     let xdg = std::env::var("XDG_DATA_HOME")
     85         .unwrap_or_else(|_| format!("{}/.local/share", dirs::home_dir().unwrap_or_default().display()));
     86     let xdg_db = format!("{}/emacs/org-roam.db", xdg);
     87     if std::path::Path::new(&xdg_db).exists() {
     88         return xdg_db;
     89     }
     90     for cand in DB_CANDIDATES {
     91         let expanded = expand_tilde(cand);
     92         if std::path::Path::new(&expanded).exists() {
     93             return expanded;
     94         }
     95     }
     96     expand_tilde(DB_CANDIDATES[0])
     97 }
     98 
     99 pub fn expand_tilde(path: &str) -> String {
    100     if let Some(rest) = path.strip_prefix("~/") {
    101         let home = dirs::home_dir().unwrap_or_default();
    102         return format!("{}/{}", home.display(), rest);
    103     }
    104     path.to_string()
    105 }