From 5036672a588a57a6c5f9cf6ce41f28a08dc0b12f Mon Sep 17 00:00:00 2001 From: pwygab <88221256+merelymyself@users.noreply.github.com> Date: Mon, 12 Dec 2022 05:22:27 +0800 Subject: [PATCH] add interact-once switch to `rm` (#7432) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Description Fixes: #7216 Adds `interact-once` switch which numbers out the number of files to delete and asks the user for confirmation. ``` /home/gabriel/test〉ls 12/11/2022 11:25:42 AM ╭───┬───────┬──────┬──────┬──────────╮ │ # │ name │ type │ size │ modified │ ├───┼───────┼──────┼──────┼──────────┤ │ 0 │ a.txt │ file │ 0 B │ now │ │ 1 │ b.txt │ file │ 0 B │ now │ │ 2 │ c.txt │ file │ 0 B │ now │ ╰───┴───────┴──────┴──────┴──────────╯ /home/gabriel/test〉rm *.txt -I 12/11/2022 11:25:42 AM rm: remove 3 files? : y /home/gabriel/test〉ls 12/11/2022 11:25:51 AM /home/gabriel/test〉 12/11/2022 11:25:54 AM ``` # User-Facing Changes _(List of all changes that impact the user experience here. This helps us keep track of breaking changes.)_ # Tests + Formatting Don't forget to add tests that cover your changes. Make sure you've run and fixed any issues with these commands: - `cargo fmt --all -- --check` to check standard code formatting (`cargo fmt --all` applies these changes) - `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A clippy::needless_collect` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass # After Submitting If your PR had any user-facing changes, update [the documentation](https://github.com/nushell/nushell.github.io) after the PR is merged, if necessary. This will help us keep the docs up to date. --- crates/nu-command/src/filesystem/cp.rs | 6 +++-- crates/nu-command/src/filesystem/mv.rs | 6 +++-- crates/nu-command/src/filesystem/rm.rs | 30 ++++++++++++++++++++++-- crates/nu-command/src/filesystem/util.rs | 4 +--- 4 files changed, 37 insertions(+), 9 deletions(-) diff --git a/crates/nu-command/src/filesystem/cp.rs b/crates/nu-command/src/filesystem/cp.rs index d9a6d1e2e4..b84d76a750 100644 --- a/crates/nu-command/src/filesystem/cp.rs +++ b/crates/nu-command/src/filesystem/cp.rs @@ -322,8 +322,10 @@ fn interactive_copy( span: Span, copy_impl: impl Fn(PathBuf, PathBuf, Span) -> Value, ) -> Value { - let (interaction, confirmed) = - try_interaction(interactive, "cp: overwrite", &dst.to_string_lossy()); + let (interaction, confirmed) = try_interaction( + interactive, + format!("cp: overwrite '{}'? ", dst.to_string_lossy()), + ); if let Err(e) = interaction { Value::Error { error: ShellError::GenericError( diff --git a/crates/nu-command/src/filesystem/mv.rs b/crates/nu-command/src/filesystem/mv.rs index 76df68bc5a..39770ba8df 100644 --- a/crates/nu-command/src/filesystem/mv.rs +++ b/crates/nu-command/src/filesystem/mv.rs @@ -283,8 +283,10 @@ fn move_file( } if interactive && to.exists() { - let (interaction, confirmed) = - try_interaction(interactive, "mv: overwrite", &to.to_string_lossy()); + let (interaction, confirmed) = try_interaction( + interactive, + format!("mv: overwrite '{}'? ", to.to_string_lossy()), + ); if let Err(e) = interaction { return Err(ShellError::GenericError( format!("Error during interaction: {:}", e), diff --git a/crates/nu-command/src/filesystem/rm.rs b/crates/nu-command/src/filesystem/rm.rs index 28e651c174..c3b336e709 100644 --- a/crates/nu-command/src/filesystem/rm.rs +++ b/crates/nu-command/src/filesystem/rm.rs @@ -65,6 +65,11 @@ impl Command for Rm { .switch("force", "suppress error when no file", Some('f')) .switch("verbose", "print names of deleted files", Some('v')) .switch("interactive", "ask user to confirm action", Some('i')) + .switch( + "interactive-once", + "ask user to confirm action only once", + Some('I'), + ) .rest( "rest", SyntaxShape::GlobPattern, @@ -138,6 +143,7 @@ fn rm( let force = call.has_flag("force"); let verbose = call.has_flag("verbose"); let interactive = call.has_flag("interactive"); + let interactive_once = call.has_flag("interactive-once") && !interactive; let ctrlc = engine_state.ctrlc.clone(); @@ -299,6 +305,24 @@ fn rm( )); } + if interactive_once { + let (interaction, confirmed) = try_interaction( + interactive_once, + format!("rm: remove {} files? ", all_targets.len()), + ); + if let Err(e) = interaction { + return Err(ShellError::GenericError( + format!("Error during interaction: {:}", e), + "could not move".into(), + None, + None, + Vec::new(), + )); + } else if !confirmed { + return Ok(PipelineData::Empty); + } + } + Ok(all_targets .into_keys() .map(move |f| { @@ -325,8 +349,10 @@ fn rm( || is_fifo || is_empty() { - let (interaction, confirmed) = - try_interaction(interactive, "rm: remove", &f.to_string_lossy()); + let (interaction, confirmed) = try_interaction( + interactive, + format!("rm: remove '{}'? ", f.to_string_lossy()), + ); let result; #[cfg(all( diff --git a/crates/nu-command/src/filesystem/util.rs b/crates/nu-command/src/filesystem/util.rs index db15c58d0a..1ef1523b24 100644 --- a/crates/nu-command/src/filesystem/util.rs +++ b/crates/nu-command/src/filesystem/util.rs @@ -90,11 +90,9 @@ impl Resource {} pub fn try_interaction( interactive: bool, - prompt_msg: &str, - file_name: &str, + prompt: String, ) -> (Result, Box>, bool) { let interaction = if interactive { - let prompt = format!("{} '{}'? ", prompt_msg, file_name); match get_interactive_confirmation(prompt) { Ok(i) => Ok(Some(i)), Err(e) => Err(e),