Initial upload with CI/CD workflow
This commit is contained in:
217
app/src/config/mod.rs
Normal file
217
app/src/config/mod.rs
Normal 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(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user