oxur_cli/config/
history.rs

1//! History configuration for the REPL
2//!
3//! Provides configuration for command history including storage path,
4//! maximum size, and enabling/disabling history.
5
6use serde::{Deserialize, Serialize};
7use std::path::PathBuf;
8
9/// History configuration
10#[derive(Debug, Clone, Serialize, Deserialize)]
11#[serde(default)]
12pub struct HistoryConfig {
13    /// Whether command history is enabled
14    pub enabled: bool,
15    /// Maximum number of history entries to keep
16    pub max_size: Option<usize>,
17    /// Custom path for history file (None uses XDG default)
18    pub path: Option<PathBuf>,
19}
20
21impl Default for HistoryConfig {
22    fn default() -> Self {
23        Self { enabled: true, max_size: Some(10000), path: None }
24    }
25}
26
27impl HistoryConfig {
28    /// Create a new builder for HistoryConfig
29    pub fn builder() -> HistoryConfigBuilder {
30        HistoryConfigBuilder::new()
31    }
32
33    /// Merge another config into this one
34    pub fn merge(&mut self, other: HistoryConfig) {
35        self.enabled = other.enabled;
36        if other.max_size.is_some() {
37            self.max_size = other.max_size;
38        }
39        if other.path.is_some() {
40            self.path = other.path;
41        }
42    }
43}
44
45/// Builder for HistoryConfig
46#[derive(Debug, Clone)]
47pub struct HistoryConfigBuilder {
48    config: HistoryConfig,
49}
50
51impl HistoryConfigBuilder {
52    /// Create a new builder with default values
53    pub fn new() -> Self {
54        Self { config: HistoryConfig::default() }
55    }
56
57    /// Enable or disable history
58    pub fn enabled(mut self, enabled: bool) -> Self {
59        self.config.enabled = enabled;
60        self
61    }
62
63    /// Set maximum history size
64    pub fn max_size(mut self, size: usize) -> Self {
65        self.config.max_size = Some(size);
66        self
67    }
68
69    /// Set custom history file path
70    pub fn path(mut self, path: impl Into<PathBuf>) -> Self {
71        self.config.path = Some(path.into());
72        self
73    }
74
75    /// Build the HistoryConfig
76    pub fn build(self) -> HistoryConfig {
77        self.config
78    }
79}
80
81impl Default for HistoryConfigBuilder {
82    fn default() -> Self {
83        Self::new()
84    }
85}
86
87#[cfg(test)]
88mod tests {
89    use super::*;
90
91    #[test]
92    fn test_default_config() {
93        let config = HistoryConfig::default();
94        assert!(config.enabled);
95        assert_eq!(config.max_size, Some(10000));
96        assert!(config.path.is_none());
97    }
98
99    #[test]
100    fn test_builder() {
101        let config =
102            HistoryConfig::builder().enabled(false).max_size(5000).path("/custom/path").build();
103
104        assert!(!config.enabled);
105        assert_eq!(config.max_size, Some(5000));
106        assert_eq!(config.path, Some(PathBuf::from("/custom/path")));
107    }
108
109    #[test]
110    fn test_serde_roundtrip() {
111        let config = HistoryConfig::builder().max_size(1000).path("/test/history").build();
112
113        let toml = toml::to_string(&config).unwrap();
114        let parsed: HistoryConfig = toml::from_str(&toml).unwrap();
115
116        assert_eq!(config.enabled, parsed.enabled);
117        assert_eq!(config.max_size, parsed.max_size);
118        assert_eq!(config.path, parsed.path);
119    }
120
121    #[test]
122    fn test_merge_preserves_none_values() {
123        let mut base = HistoryConfig::builder().max_size(5000).path("/base/path").build();
124
125        let other = HistoryConfig { enabled: false, max_size: None, path: None };
126
127        base.merge(other);
128
129        assert!(!base.enabled);
130        assert_eq!(base.max_size, Some(5000)); // Preserved
131        assert_eq!(base.path, Some(PathBuf::from("/base/path"))); // Preserved
132    }
133
134    #[test]
135    fn test_merge_overrides_some_values() {
136        let mut base = HistoryConfig::builder().max_size(5000).build();
137
138        let other = HistoryConfig::builder().max_size(1000).path("/new/path").build();
139
140        base.merge(other);
141
142        assert_eq!(base.max_size, Some(1000));
143        assert_eq!(base.path, Some(PathBuf::from("/new/path")));
144    }
145}