diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/config/mod.rs | 84 | ||||
| -rw-r--r-- | src/repl/mod.rs | 11 |
2 files changed, 89 insertions, 6 deletions
diff --git a/src/config/mod.rs b/src/config/mod.rs index dae2018..a92c65f 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -19,7 +19,7 @@ use crate::utils::*; use anyhow::{anyhow, bail, Context, Result}; use indexmap::IndexMap; -use inquire::{validator::Validation, Confirm, Select, Text}; +use inquire::{list_option::ListOption, validator::Validation, Confirm, MultiSelect, Select, Text}; use parking_lot::RwLock; use serde::Deserialize; use serde_json::json; @@ -27,7 +27,9 @@ use simplelog::LevelFilter; use std::collections::{HashMap, HashSet}; use std::{ env, - fs::{create_dir_all, read_dir, read_to_string, remove_file, File, OpenOptions}, + fs::{ + create_dir_all, read_dir, read_to_string, remove_dir_all, remove_file, File, OpenOptions, + }, io::Write, path::{Path, PathBuf}, process, @@ -624,11 +626,79 @@ impl Config { let value = value.parse().with_context(|| "Invalid value")?; config.write().highlight = value; } - _ => bail!("Unknown key `{key}`"), + _ => bail!("Unknown key '{key}'"), } Ok(()) } + pub fn delete(config: &GlobalConfig, kind: &str) -> Result<()> { + let (dir, file_ext) = match kind { + "roles" => (Self::roles_dir()?, Some(".md")), + "sessions" => (config.read().sessions_dir()?, Some(".yaml")), + "rags" => (Self::rags_dir()?, Some(".yaml")), + "agents-config" => (Self::agents_config_dir()?, None), + _ => bail!("Unknown kind '{kind}'"), + }; + let names = match read_dir(&dir) { + Ok(rd) => { + let mut names = vec![]; + for entry in rd.flatten() { + let name = entry.file_name(); + match file_ext { + Some(file_ext) => { + if let Some(name) = name.to_string_lossy().strip_suffix(file_ext) { + names.push(name.to_string()); + } + } + None => { + if entry.path().is_dir() { + names.push(name.to_string_lossy().to_string()); + } + } + } + } + names.sort_unstable(); + names + } + Err(_) => vec![], + }; + + if names.is_empty() { + bail!("No {kind} to delete") + } + + let select_names = MultiSelect::new(&format!("Select {kind} to delete:"), names) + .with_validator(|list: &[ListOption<&String>]| { + if list.is_empty() { + Ok(Validation::Invalid( + "At least one item must be selected".into(), + )) + } else { + Ok(Validation::Valid) + } + }) + .prompt()?; + + for name in select_names { + match file_ext { + Some(ext) => { + let path = dir.join(format!("{name}{ext}")); + remove_file(&path).with_context(|| { + format!("Failed to delete {kind} at '{}'", path.display()) + })?; + } + None => { + let path = dir.join(name); + remove_dir_all(&path).with_context(|| { + format!("Failed to delete {kind} at '{}'", path.display()) + })?; + } + } + } + println!("✨ Successfully deleted {kind}."); + Ok(()) + } + pub fn set_temperature(&mut self, value: Option<f64>) { match self.role_like_mut() { Some(role_like) => role_like.set_temperature(value), @@ -1432,6 +1502,10 @@ impl Config { .into_iter() .map(|v| (format!("{v} "), None)) .collect(), + ".delete" => vec!["roles", "sessions", "rags", "agents-config"] + .into_iter() + .map(|v| (v.to_string(), None)) + .collect(), _ => vec![], }; filter = args[0] @@ -1505,7 +1579,7 @@ impl Config { let theme_path = Self::local_path(&theme_filename)?; if theme_path.exists() { let theme = ThemeSet::get_theme(&theme_path) - .with_context(|| format!("Invalid theme at {}", theme_path.display()))?; + .with_context(|| format!("Invalid theme at '{}'", theme_path.display()))?; Some(theme) } else { let theme = if self.light_theme { @@ -1703,7 +1777,7 @@ impl Config { fn load_from_file(config_path: &Path) -> Result<Self> { let content = read_to_string(config_path) - .with_context(|| format!("Failed to load config at {}", config_path.display()))?; + .with_context(|| format!("Failed to load config at '{}'", config_path.display()))?; let config: Self = serde_yaml::from_str(&content).map_err(|err| { let err_msg = err.to_string(); let err_msg = if err_msg.starts_with(&format!("{}: ", CLIENTS_FIELD)) { diff --git a/src/repl/mod.rs b/src/repl/mod.rs index 8c68f78..13e147b 100644 --- a/src/repl/mod.rs +++ b/src/repl/mod.rs @@ -31,7 +31,7 @@ lazy_static::lazy_static! { const MENU_NAME: &str = "completion_menu"; lazy_static::lazy_static! { - static ref REPL_COMMANDS: [ReplCommand; 30] = [ + static ref REPL_COMMANDS: [ReplCommand; 31] = [ ReplCommand::new(".help", "Show this help message", AssertState::pass()), ReplCommand::new(".info", "View system info", AssertState::pass()), ReplCommand::new(".model", "Change the current LLM", AssertState::pass()), @@ -148,6 +148,7 @@ lazy_static::lazy_static! { AssertState::pass() ), ReplCommand::new(".set", "Adjust settings", AssertState::pass()), + ReplCommand::new(".delete", "Delete roles/sessions/RAGs/agents-config", AssertState::pass()), ReplCommand::new(".copy", "Copy the last response", AssertState::pass()), ReplCommand::new(".exit", "Exit the REPL", AssertState::pass()), ]; @@ -392,6 +393,14 @@ impl Repl { println!("Usage: .set <key> <value>...") } }, + ".delete" => match args { + Some(args) => { + Config::delete(&self.config, args)?; + } + _ => { + println!("Usage: .delete [roles|sessions|rags|agents-config]") + } + }, ".copy" => { let config = self.config.read(); self.copy(config.last_reply()) |
