From 2f83d476ed7d5bd41ebc659c06b0f8bcb8c35812 Mon Sep 17 00:00:00 2001 From: 7000pctAUTO Date: Tue, 3 Feb 2026 09:41:16 +0000 Subject: [PATCH] Initial upload with CI/CD workflow --- app/src/config/mod.rs | 217 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 217 insertions(+) create mode 100644 app/src/config/mod.rs diff --git a/app/src/config/mod.rs b/app/src/config/mod.rs new file mode 100644 index 0000000..93626eb --- /dev/null +++ b/app/src/config/mod.rs @@ -0,0 +1,217 @@ +use anyhow::{Result, Context}; +use serde::{Serialize, Deserialize}; +use std::fs; +use std::path::PathBuf; +use std::collections::HashMap; + +use crate::parser::{CommandInfo, Argument}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct AppConfig { + pub theme: ThemeConfig, + pub keybindings: KeyBindings, + pub defaults: DefaultsConfig, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ThemeConfig { + pub primary_color: String, + pub secondary_color: String, + pub accent_color: String, + pub background_color: String, + pub text_color: String, + pub border_style: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct KeyBindings { + pub up: String, + pub down: String, + pub left: String, + pub right: String, + pub enter: String, + pub escape: String, + pub search: String, + pub help: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct DefaultsConfig { + pub show_hidden: bool, + pub auto_preview: bool, + pub max_examples: usize, + pub syntax_highlighting: bool, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct WorkflowStep { + pub name: String, + pub command_template: String, + pub description: String, + pub arguments: HashMap, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SavedConfig { + pub name: String, + pub command_info: CommandInfo, + pub workflows: Vec, + pub custom_args: Vec<(String, String)>, + pub created_at: String, + pub updated_at: String, +} + +pub struct ConfigManager; + +impl Default for AppConfig { + fn default() -> Self { + Self { + theme: ThemeConfig { + primary_color: "#3b82f6".to_string(), + secondary_color: "#64748b".to_string(), + accent_color: "#22c55e".to_string(), + background_color: "#0f172a".to_string(), + text_color: "#e2e8f0".to_string(), + border_style: "round".to_string(), + }, + keybindings: KeyBindings { + up: "Up".to_string(), + down: "Down".to_string(), + left: "Left".to_string(), + right: "Right".to_string(), + enter: "Enter".to_string(), + escape: "Esc".to_string(), + search: "/".to_string(), + help: "?".to_string(), + }, + defaults: DefaultsConfig { + show_hidden: false, + auto_preview: true, + max_examples: 5, + syntax_highlighting: true, + }, + } + } +} + +impl Default for Config { + fn default() -> Self { + Self { + config: AppConfig::default(), + saved_commands: HashMap::new(), + recent_commands: Vec::new(), + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Config { + pub config: AppConfig, + pub saved_commands: HashMap, + pub recent_commands: Vec, +} + +impl Config { + pub fn load_or_default() -> Result { + let config_path = Self::get_config_path()?; + + if config_path.exists() { + Self::load_from_file(&config_path) + } else { + let default_config = Self::default(); + default_config.save()?; + Ok(default_config) + } + } + + fn get_config_path() -> Result { + if let Ok(path) = std::env::var("TUI_GEN_CONFIG_DIR") { + Ok(PathBuf::from(path)) + } else { + let home = std::env::var("HOME") + .context("Neither TUI_GEN_CONFIG_DIR nor HOME is set")?; + Ok(PathBuf::from(home).join(".config").join("tui-generator")) + } + } + + fn load_from_file(path: &PathBuf) -> Result { + let content = fs::read_to_string(path) + .with_context(|| format!("Failed to read config from {}", path.display()))?; + toml::from_str(&content) + .with_context(|| "Failed to parse config file") + } + + pub fn save(&self) -> Result<()> { + let config_path = Self::get_config_path()?; + fs::create_dir_all(&config_path) + .with_context(|| format!("Failed to create config directory {}", config_path.display()))?; + + let content = toml::to_string_pretty(self) + .context("Failed to serialize config")?; + fs::write(config_path.join("config.toml"), content) + .context("Failed to write config file")?; + + Ok(()) + } + + pub fn add_recent_command(&mut self, command: String) { + self.recent_commands.retain(|c| c != &command); + self.recent_commands.insert(0, command); + if self.recent_commands.len() > 10 { + self.recent_commands.pop(); + } + let _ = self.save(); + } +} + +impl ConfigManager { + pub fn export_config(command_info: &CommandInfo, output: &PathBuf) -> Result<()> { + let saved = SavedConfig { + name: command_info.name.clone(), + command_info: command_info.clone(), + workflows: Vec::new(), + custom_args: Vec::new(), + created_at: chrono::Utc::now().to_rfc3339(), + updated_at: chrono::Utc::now().to_rfc3339(), + }; + + let content = toml::to_string_pretty(&saved) + .context("Failed to serialize config")?; + fs::write(output, content) + .with_context(|| format!("Failed to write to {}", output.display()))?; + + Ok(()) + } + + pub fn list_saved_configs() -> Result> { + let config = Config::load_or_default()?; + Ok(config.saved_commands.keys().cloned().collect()) + } + + pub fn load_config(name: &str) -> Result> { + let config = Config::load_or_default()?; + if let Some(saved) = config.saved_commands.get(name) { + Ok(Some(saved.command_info.clone())) + } else { + Ok(None) + } + } + + pub fn save_command_config(name: &str, command_info: CommandInfo) -> Result<()> { + let mut config = Config::load_or_default()?; + + let saved = SavedConfig { + name: name.to_string(), + command_info, + workflows: Vec::new(), + custom_args: Vec::new(), + created_at: chrono::Utc::now().to_rfc3339(), + updated_at: chrono::Utc::now().to_rfc3339(), + }; + + config.saved_commands.insert(name.to_string(), saved); + config.save()?; + + Ok(()) + } +}