diff --git a/README.md b/README.md index 67783c8..225a35a 100644 --- a/README.md +++ b/README.md @@ -120,9 +120,10 @@ If Config::version_sync_file_location is set, the version in that file will be p --- -- `bob uninstall |nightly|stable|latest|||` +- `bob uninstall [|nightly|stable|latest|||]` -Uninstall the specified version. +Uninstall the specified version. If no version is specified a prompt is used to select all the versions +to be uninstalled. --- diff --git a/src/cli.rs b/src/cli.rs index f521dd6..ad2df56 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -60,8 +60,9 @@ enum Cli { /// Uninstall the specified version #[clap(visible_alias = "rm")] Uninstall { - /// Version to be uninstalled |nightly|stable||| - version: String, + /// Optional Version to be uninstalled |nightly|stable||| + /// If no Version is provided a prompt is used to select the versions to be uninstalled + version: Option, }, /// Rollback to an existing nightly rollback @@ -134,7 +135,7 @@ pub async fn start(config: Config) -> Result<()> { } Cli::Uninstall { version } => { info!("Starting uninstallation process"); - uninstall_handler::start(&version, config).await?; + uninstall_handler::start(version.as_deref(), config).await?; } Cli::Rollback => rollback_handler::start(config).await?, Cli::Erase => erase_handler::start(config).await?, diff --git a/src/handlers/uninstall_handler.rs b/src/handlers/uninstall_handler.rs index 7164650..bb7c31b 100644 --- a/src/handlers/uninstall_handler.rs +++ b/src/handlers/uninstall_handler.rs @@ -1,4 +1,9 @@ use anyhow::{anyhow, Result}; +use dialoguer::{ + console::{style, Term}, + theme::ColorfulTheme, + Confirm, MultiSelect, +}; use reqwest::Client; use tokio::fs; use tracing::{info, warn}; @@ -8,10 +13,15 @@ use crate::{ helpers::{self, directories}, }; -pub async fn start(version: &str, config: Config) -> Result<()> { +pub async fn start(version: Option<&str>, config: Config) -> Result<()> { let client = Client::new(); - let version = helpers::version::parse_version_type(&client, version).await?; + let version = match version { + Some(value) => value, + None => return uninstall_selections(&client, &config).await, + }; + + let version = helpers::version::parse_version_type(&client, version).await?; if helpers::version::is_version_used(&version.tag_name, &config).await { warn!("Switch to a different version before proceeding"); return Ok(()); @@ -28,3 +38,67 @@ pub async fn start(version: &str, config: Config) -> Result<()> { info!("Successfully uninstalled version: {}", version.tag_name); Ok(()) } + +async fn uninstall_selections(client: &Client, config: &Config) -> Result<()> { + let downloads_dir = directories::get_downloads_directory(config).await?; + + let mut paths = fs::read_dir(downloads_dir.clone()).await?; + let mut installed_versions: Vec = Vec::new(); + + while let Some(path) = paths.next_entry().await? { + let name = path.file_name().to_str().unwrap().to_owned(); + + let version = match helpers::version::parse_version_type(client, &name).await { + Ok(value) => value, + Err(_) => continue, + }; + + if helpers::version::is_version_used(&version.tag_name, config).await { + continue; + } + installed_versions.push(version.tag_name); + } + + if installed_versions.is_empty() { + info!("You only have one neovim instance installed"); + return Ok(()); + } + + let theme = ColorfulTheme { + checked_item_prefix: style("✓".to_string()).for_stderr().green(), + unchecked_item_prefix: style("✓".to_string()).for_stderr().black(), + ..ColorfulTheme::default() + }; + + let selections = MultiSelect::with_theme(&theme) + .with_prompt("Toogle with space the versions you wish to uninstall:") + .items(&installed_versions) + .interact_on_opt(&Term::stderr())?; + + match &selections { + Some(ids) if !ids.is_empty() => { + let confirm = Confirm::with_theme(&ColorfulTheme::default()) + .with_prompt("Do you wish to continue?") + .interact_on_opt(&Term::stderr())?; + + match confirm { + Some(true) => {} + None | Some(false) => { + info!("Uninstall aborted..."); + return Ok(()); + } + } + + for &i in ids { + let path = downloads_dir.join(&installed_versions[i]); + fs::remove_dir_all(path).await?; + info!( + "Successfully uninstalled version: {}", + &installed_versions[i] + ); + } + } + None | Some(_) => info!("Uninstall aborted..."), + } + Ok(()) +}