mod history;
mod loader;
mod metrics;
pub mod paths;
mod terminal;
pub use history::{HistoryConfig, HistoryConfigBuilder};
pub use loader::{load_config, ConfigLoader};
pub use metrics::{MetricsConfig, MetricsConfigBuilder};
pub use terminal::{EditMode, TerminalConfig, TerminalConfigBuilder};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(default)]
pub struct ReplConfig {
pub terminal: TerminalConfig,
pub history: HistoryConfig,
pub metrics: MetricsConfig,
}
impl ReplConfig {
pub fn load(no_color: bool) -> anyhow::Result<Self> {
load_config(no_color)
}
pub fn builder() -> ReplConfigBuilder {
ReplConfigBuilder::new()
}
pub fn merge(&mut self, other: ReplConfig) {
self.terminal.merge(other.terminal);
self.history.merge(other.history);
self.metrics.merge(other.metrics);
}
}
#[derive(Debug, Clone, Default)]
pub struct ReplConfigBuilder {
config: ReplConfig,
}
impl ReplConfigBuilder {
pub fn new() -> Self {
Self { config: ReplConfig::default() }
}
pub fn terminal(mut self, config: TerminalConfig) -> Self {
self.config.terminal = config;
self
}
pub fn history(mut self, config: HistoryConfig) -> Self {
self.config.history = config;
self
}
pub fn metrics(mut self, config: MetricsConfig) -> Self {
self.config.metrics = config;
self
}
pub fn build(self) -> ReplConfig {
self.config
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_repl_config_default() {
let config = ReplConfig::default();
assert_eq!(config.terminal.prompt, "oxur> ");
assert!(config.history.enabled);
}
#[test]
fn test_repl_config_builder() {
let terminal = TerminalConfig::builder().prompt(">>> ").build();
let history = HistoryConfig::builder().max_size(500).build();
let config = ReplConfig::builder().terminal(terminal).history(history).build();
assert_eq!(config.terminal.prompt, ">>> ");
assert_eq!(config.history.max_size, Some(500));
}
#[test]
fn test_serde_roundtrip() {
let config = ReplConfig::builder()
.terminal(TerminalConfig::builder().prompt("test> ").build())
.build();
let toml = toml::to_string(&config).unwrap();
let parsed: ReplConfig = toml::from_str(&toml).unwrap();
assert_eq!(config.terminal.prompt, parsed.terminal.prompt);
}
#[test]
fn test_merge() {
let mut base = ReplConfig::default();
let other = ReplConfig::builder()
.terminal(TerminalConfig::builder().prompt("merged> ").build())
.build();
base.merge(other);
assert_eq!(base.terminal.prompt, "merged> ");
}
#[test]
fn test_toml_parsing() {
let toml_str = r#"
[terminal]
prompt = "λ> "
continuation_prompt = " | "
color_enabled = true
edit_mode = "vi"
[history]
enabled = true
max_size = 5000
"#;
let config: ReplConfig = toml::from_str(toml_str).unwrap();
assert_eq!(config.terminal.prompt, "λ> ");
assert_eq!(config.terminal.continuation_prompt, " | ");
assert_eq!(config.terminal.edit_mode, EditMode::Vi);
assert_eq!(config.history.max_size, Some(5000));
}
}