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}