Initial upload with CI/CD workflow
Some checks failed
CI / test (push) Has been cancelled
CI / build (push) Has been cancelled

This commit is contained in:
2026-02-03 09:41:16 +00:00
parent 3d702c768a
commit 2f83d476ed

217
app/src/config/mod.rs Normal file
View File

@@ -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<String, String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SavedConfig {
pub name: String,
pub command_info: CommandInfo,
pub workflows: Vec<WorkflowStep>,
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<String, SavedConfig>,
pub recent_commands: Vec<String>,
}
impl Config {
pub fn load_or_default() -> Result<Self> {
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<PathBuf> {
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<Self> {
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<Vec<String>> {
let config = Config::load_or_default()?;
Ok(config.saved_commands.keys().cloned().collect())
}
pub fn load_config(name: &str) -> Result<Option<CommandInfo>> {
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(())
}
}