Skip to main content

iris_reader/
config.rs

1use std::{fs, path::PathBuf};
2
3use anyhow::{Context, Result};
4use serde::Deserialize;
5
6use crate::{cli::Cli, options::IconMode};
7
8#[derive(Debug, Clone, Deserialize)]
9#[serde(default)]
10pub struct Config {
11    pub theme: String,
12    pub wrap: bool,
13    pub tab_width: usize,
14    pub icons: IconMode,
15}
16
17impl Default for Config {
18    fn default() -> Self {
19        Self {
20            theme: "ember".to_string(),
21            wrap: true,
22            tab_width: 4,
23            icons: IconMode::NerdFont,
24        }
25    }
26}
27
28impl Config {
29    pub fn load() -> Result<Self> {
30        let Some(path) = config_path() else {
31            return Ok(Self::default());
32        };
33
34        if !path.exists() {
35            return Ok(Self::default());
36        }
37
38        let source = fs::read_to_string(&path)
39            .with_context(|| format!("failed to read config '{}'", path.display()))?;
40        let mut config: Self = toml::from_str(&source)
41            .with_context(|| format!("invalid config '{}'", path.display()))?;
42        config.tab_width = config.tab_width.clamp(1, 16);
43        Ok(config)
44    }
45
46    pub fn apply_cli(mut self, cli: &Cli) -> Self {
47        if let Some(theme) = &cli.theme {
48            self.theme = theme.clone();
49        }
50        if cli.wrap {
51            self.wrap = true;
52        }
53        if cli.no_wrap {
54            self.wrap = false;
55        }
56        if let Some(icons) = cli.icons {
57            self.icons = icons;
58        }
59        self
60    }
61}
62
63pub fn config_path() -> Option<PathBuf> {
64    dirs::config_dir().map(|dir| dir.join("iris").join("config.toml"))
65}