1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
use crate::cmus_status::output::Format;
use crate::error::prelude::*;
use std::fs::File;
use std::io::Read;
use std::path::PathBuf;

pub const DEFAULT_CONFIG: &str = include_str!("../../config.toml");
const KEYWORD_CONFIG_DIR: &str = "<CONFIG_DIR>";
const CONFIG_FILES: [&str; 2] = ["./config.toml", "<CONFIG_DIR>/config.toml"];

#[derive(Deserialize)]
pub struct Config {
    pub format: Format,
}

impl Config {
    fn from_toml(toml: &str) -> MyResult<Self> {
        toml::de::from_str(toml)
            .or_else(|e| Err(Error::FailedParsingConfig(None, e.to_string())))
    }
}

pub fn get_config() -> MyResult<Config> {
    if let Some(conf_path) = get_config_file() {
        if let Ok(mut file) = File::open(&conf_path) {
            let mut file_content = String::new();
            file.read_to_string(&mut file_content).unwrap();
            Config::from_toml(file_content.as_str()).map_err(|e| {
                if let Error::FailedParsingConfig(None, msg) = e {
                    Error::FailedParsingConfig(Some(conf_path), msg)
                } else {
                    e
                }
            })
        } else {
            default_config()
        }
    } else {
        default_config()
    }
}

fn default_config() -> MyResult<Config> {
    Config::from_toml(DEFAULT_CONFIG)
}

fn get_config_file() -> Option<PathBuf> {
    CONFIG_FILES.iter().find_map(|filepath| {
        let path = if filepath.starts_with(KEYWORD_CONFIG_DIR) {
            let filepath_without_keyword = filepath
                .replace(&format!("{}/", KEYWORD_CONFIG_DIR), "")
                .replace(KEYWORD_CONFIG_DIR, "");
            if let Some(mut path) = get_config_dir() {
                path.push(filepath_without_keyword);
                path
            } else {
                PathBuf::from(filepath_without_keyword)
            }
        } else {
            PathBuf::from(filepath)
        };
        if path.is_file() {
            Some(path)
        } else {
            None
        }
    })
}

fn get_config_dir() -> Option<PathBuf> {
    dirs::config_dir().map(|mut d| {
        d.push(crate::meta::NAME);
        d
    })
}