pre/
config.rs

1use anyhow::{Result, bail};
2use serde::{Serialize, Deserialize};
3
4use std::collections::HashMap;
5use std::fs::{self, File};
6use std::io::{self, Read, Write};
7use std::path::PathBuf;
8
9#[derive(Default, Serialize, Deserialize)]
10pub struct ChronicleConfig {
11    pub stores: Vec<String>,
12    pub reverse: Option<bool>,
13    pub date: Option<String>,
14    pub time: Option<String>,
15}
16
17impl ChronicleConfig {
18    pub fn new(store: &str) -> Self {
19        Self {
20            stores: vec![store.to_string()],
21            ..Default::default()
22        }
23    }
24}
25
26fn reverse_default() -> bool { true }
27fn date_default() -> String { String::from("%Y-%m-%d") }
28fn time_default() -> String { String::from("%H:%M") }
29
30#[derive(Default, Serialize, Deserialize)]
31pub struct Config {
32    pub editor: String,
33    #[serde(default = "reverse_default")]
34    pub reverse: bool,
35    #[serde(default = "date_default")]
36    pub date: String,
37    #[serde(default = "time_default")]
38    pub time: String,
39    pub chronicle: HashMap<String, ChronicleConfig>,
40}
41
42impl Config {
43    pub fn new() -> Self {
44        Self {
45            reverse: reverse_default(),
46            date: date_default(),
47            time: time_default(),
48            ..Default::default()
49        }
50    }
51
52    pub fn exists(&self, name: &str) -> bool {
53        self.chronicle.contains_key(name)
54    }
55}
56
57pub fn dir() -> PathBuf {
58    home::home_dir().unwrap().join(".chronicle")
59}
60
61pub fn backup_dir() -> PathBuf {
62    dir().join("backup~")
63}
64
65pub fn config_path() -> PathBuf {
66    dir().join("config.toml")
67}
68
69pub fn draft_path(name: &str) -> PathBuf {
70    dir().join(name)
71}
72
73fn init_config() -> Result<()> {
74    let d = dir();
75    fs::create_dir_all(&d)?;
76    let p = config_path();
77    let mut f = File::create(&p)?;
78
79    let c = Config::new();
80    let b = toml::to_vec(&c)?;
81    f.write_all(&b)?;
82    Ok(())
83}
84
85pub fn read_config() -> Result<Config> {
86    let p = config_path();
87    let f = File::open(&p).or_else(|err| {
88        match err.kind() {
89            io::ErrorKind::NotFound => {
90                init_config().and_then(|()| {
91                    File::open(&p)
92                        .map_err(|e| e.into())
93                })
94            },
95            _ => Err(anyhow::Error::from(err))
96        }
97    });
98
99    if let Err(e) = f {
100        bail!(e);
101    }
102
103    let mut f = f?;
104    let mut s = String::new();
105    f.read_to_string(&mut s)?;
106
107    toml::from_str(&s)
108        .map_err(|e| e.into())
109}
110
111pub fn write_config(cfg: &mut Config) -> Result<()> {
112    let p = config_path();
113    let b = toml::to_vec(cfg)?;
114    fs::write(&p, &b)?;
115    Ok(())
116}