steer_core/
preferences.rs1use serde::{Deserialize, Serialize};
2use std::path::PathBuf;
3
4#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Default)]
5pub enum EditingMode {
6 #[default]
7 Simple, Vim, }
10
11#[derive(Debug, Clone, Serialize, Deserialize, Default)]
12pub struct Preferences {
13 #[serde(default)]
14 pub ui: UiPreferences,
15
16 #[serde(default)]
17 pub keybindings: KeyBindings,
18
19 #[serde(default)]
20 pub tools: ToolPreferences,
21}
22
23#[derive(Debug, Clone, Serialize, Deserialize, Default)]
24pub struct UiPreferences {
25 pub default_model: Option<String>,
26 pub theme: Option<String>,
27 pub notifications: NotificationPreferences,
28 pub history_limit: Option<usize>,
29 pub provider_priority: Option<Vec<String>>,
30 #[serde(default)]
31 pub editing_mode: EditingMode,
32}
33
34#[derive(Debug, Clone, Serialize, Deserialize)]
35pub struct NotificationPreferences {
36 pub sound: bool,
37 pub desktop: bool,
38}
39
40#[derive(Debug, Clone, Serialize, Deserialize, Default)]
41pub struct KeyBindings {
42 pub cancel: Option<String>,
43 pub model_selection: Option<String>,
44 pub clear: Option<String>,
45}
46
47#[derive(Debug, Clone, Serialize, Deserialize, Default)]
48pub struct ToolPreferences {
49 pub pre_approved: Vec<String>,
50}
51
52impl Default for NotificationPreferences {
53 fn default() -> Self {
54 Self {
55 sound: true,
56 desktop: true,
57 }
58 }
59}
60
61impl Preferences {
62 pub fn config_path() -> Result<PathBuf, crate::error::Error> {
64 let config_dir = dirs::config_dir().ok_or_else(|| {
65 crate::error::Error::Configuration("Could not determine config directory".to_string())
66 })?;
67 Ok(config_dir.join("steer").join("preferences.toml"))
68 }
69
70 pub fn load() -> Result<Self, crate::error::Error> {
72 let path = Self::config_path()?;
73
74 if path.exists() {
75 let contents = std::fs::read_to_string(&path)?;
76 match toml::from_str(&contents) {
77 Ok(prefs) => Ok(prefs),
78 Err(e) => {
79 tracing::warn!(
80 "Failed to parse preferences file at {:?}: {}. Using defaults.",
81 path,
82 e
83 );
84 Ok(Self::default())
85 }
86 }
87 } else {
88 Ok(Self::default())
89 }
90 }
91
92 pub fn save(&self) -> Result<(), crate::error::Error> {
94 let path = Self::config_path()?;
95
96 if let Some(parent) = path.parent() {
98 std::fs::create_dir_all(parent)?;
99 }
100
101 let contents = toml::to_string_pretty(self).map_err(|e| {
102 crate::error::Error::Configuration(format!("Failed to serialize preferences: {e}"))
103 })?;
104
105 std::fs::write(&path, contents)?;
106
107 Ok(())
108 }
109}