1use anyhow::{Context, Result};
2use serde::{Deserialize, Serialize};
3use std::path::PathBuf;
4use crate::theme::ThemeName;
5
6#[derive(Debug, Deserialize, Serialize)]
7pub struct Config {
8 #[serde(default)]
9 pub keybindings: KeyBindings,
10 #[serde(default)]
11 pub theme: ThemeName,
12}
13
14#[derive(Debug, Deserialize, Serialize)]
15pub struct KeyBindings {
16 #[serde(default = "default_quit")]
17 pub quit: char,
18 #[serde(default = "default_open")]
19 pub open: char,
20 #[serde(default = "default_open_new_tab")]
21 pub open_new_tab: char,
22 #[serde(default = "default_refresh")]
23 pub refresh: char,
24 #[serde(default = "default_latest")]
25 pub latest: char,
26 #[serde(default = "default_scroll_up")]
27 pub scroll_up: char,
28 #[serde(default = "default_scroll_down")]
29 pub scroll_down: char,
30 #[serde(default = "default_scroll_bottom")]
31 pub scroll_bottom: char,
32}
33
34fn default_quit() -> char { 'q' }
35fn default_open() -> char { 'o' }
36fn default_open_new_tab() -> char { 'O' }
37fn default_refresh() -> char { 'r' }
38fn default_latest() -> char { 'l' }
39fn default_scroll_up() -> char { 'k' }
40fn default_scroll_down() -> char { 'j' }
41fn default_scroll_bottom() -> char { 'G' }
42
43impl Default for KeyBindings {
44 fn default() -> Self {
45 Self {
46 quit: default_quit(),
47 open: default_open(),
48 open_new_tab: default_open_new_tab(),
49 refresh: default_refresh(),
50 latest: default_latest(),
51 scroll_up: default_scroll_up(),
52 scroll_down: default_scroll_down(),
53 scroll_bottom: default_scroll_bottom(),
54 }
55 }
56}
57
58impl Default for Config {
59 fn default() -> Self {
60 Self {
61 keybindings: KeyBindings::default(),
62 theme: ThemeName::default(),
63 }
64 }
65}
66
67pub fn load_config() -> Result<Config> {
68 let config_path = get_config_path()?;
69
70 if !config_path.exists() {
71 return Ok(Config::default());
72 }
73
74 let content = std::fs::read_to_string(&config_path)
75 .context("Failed to read config file")?;
76
77 let config: Config = toml::from_str(&content)
78 .context("Failed to parse config file")?;
79
80 Ok(config)
81}
82
83fn get_config_path() -> Result<PathBuf> {
84 if let Some(home) = dirs::home_dir() {
86 let bbcli_path = home.join(".bbcli");
87 if bbcli_path.exists() {
88 return Ok(bbcli_path);
89 }
90 }
91
92 if let Some(config_dir) = dirs::config_dir() {
94 let bbcli_config = config_dir.join("bbcli");
95 return Ok(bbcli_config);
96 }
97
98 dirs::home_dir()
100 .map(|h| h.join(".bbcli"))
101 .context("Could not determine config path")
102}