From a9ea86f3f8c9cba5e453b7a50894da682e022ba8 Mon Sep 17 00:00:00 2001 From: sigoden Date: Fri, 13 Sep 2024 09:08:43 +0800 Subject: feat: add `.delete` repl command (#862) --- src/config/mod.rs | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 79 insertions(+), 5 deletions(-) (limited to 'src/config/mod.rs') 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) { 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 { 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)) { -- cgit v1.2.3