From 382803c803c5e052fb38507f1440aa4341605c5a Mon Sep 17 00:00:00 2001 From: Nikita Revenco <154856872+NikitaRevenco@users.noreply.github.com> Date: Tue, 18 Feb 2025 12:15:35 +0000 Subject: [PATCH] feat: add confirmation prompt when overwriting --- helix-term/src/ui/mod.rs | 144 +++++++++++++++++++++++++++++---------- 1 file changed, 108 insertions(+), 36 deletions(-) diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index bd7a2e441..a0cf06a3a 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -286,6 +286,39 @@ pub fn file_picker(root: PathBuf, config: &helix_view::editor::Config) -> FilePi type FileExplorer = Picker<(PathBuf, bool), (PathBuf, Style)>; +fn create_confirmation_prompt( + input: String, + cx: &mut Context, + to_create_str: String, + to_create: PathBuf, + callback: fn(&str, &Path) -> Option>, +) { + let callback = Box::pin(async move { + let call: Callback = Callback::EditorCompositor(Box::new(move |_editor, compositor| { + let prompt = Prompt::new( + input.into(), + None, + crate::ui::completers::none, + move |cx, input: &str, event: PromptEvent| { + if event != PromptEvent::Validate || input != "y" { + return; + }; + + match callback(&to_create_str, &to_create) { + Some(Ok(msg)) => cx.editor.set_status(msg), + Some(Err(msg)) => cx.editor.set_error(msg), + None => (), + }; + }, + ); + + compositor.push(Box::new(prompt)); + })); + Ok(call) + }); + cx.jobs.callback(callback); +} + fn create_file_operation_prompt( prompt: &'static str, cx: &mut Context, @@ -381,42 +414,52 @@ pub fn file_explorer(root: PathBuf, editor: &Editor) -> Result { - create_file_operation_prompt("create:", cx, path, |_cx, _path, to_create_str| { + create_file_operation_prompt("create:", cx, path, |cx, _path, to_create_str| { let to_create = helix_stdx::path::expand_tilde(PathBuf::from(to_create_str)); - if to_create.exists() { - // TODO: confirmation prompt - return Some(Err(format!("Path {} already exists", to_create.display()))) + let create = |to_create_str: &str, to_create: &Path| { + if to_create_str.ends_with(std::path::MAIN_SEPARATOR) { + if let Err(err) = fs::create_dir_all(to_create).map_err( + |err| format!("Unable to create directory {}: {err}", to_create.display()) + ) { + return Some(Err(err)); + } + + Some(Ok(format!("Created directory: {}", to_create.display()))) + } else { + if let Err(err) = fs::File::create(to_create).map_err( + |err| format!("Unable to create file {}: {err}", to_create.display()) + ) { + return Some(Err(err)); + }; + + Some(Ok(format!("Created file: {}", to_create.display()))) + } }; - if to_create_str.ends_with(std::path::MAIN_SEPARATOR) { - if let Err(err) = fs::create_dir_all(&to_create).map_err( - |err| format!("Unable to create directory {}: {err}", to_create.display()) - ) { - return Some(Err(err)); - } + if to_create.exists() { + create_confirmation_prompt( + format!( + "Path {} already exists. Overwrite? (y/n):", to_create.display() + ), + cx, + to_create_str.to_string(), + to_create.to_path_buf(), + create + ); + return None; + }; - Some(Ok(format!("Created directory: {}", to_create.display()))) - } else { - if let Err(err) = fs::File::create(&to_create).map_err( - |err| format!("Unable to create file {}: {err}", to_create.display()) - ) { - return Some(Err(err)); - }; - - Some(Ok(format!("Created file: {}", to_create.display()))) - } + create(to_create_str, &to_create) }) }, // move alt!('m') => { - create_file_operation_prompt("move:", cx, path, |_, move_from, move_to_str| { + create_file_operation_prompt("move:", cx, path, |cx, move_from, move_to_str| { let move_to = helix_stdx::path::expand_tilde(PathBuf::from(move_to_str)); - if move_to.exists() { - // TODO: confirmation prompt - Some(Err(format!("Path {} already exists", move_to.display()))) - } else { + let move_op = |move_to_str: &str, move_from: &Path| { + let move_to = helix_stdx::path::expand_tilde(PathBuf::from(move_to_str)); if let Err(err) = fs::rename(move_from, &move_to).map_err(|err| format!( "Unable to move {} {} -> {}: {err}", @@ -432,7 +475,22 @@ pub fn file_explorer(root: PathBuf, editor: &Editor) -> Result Result { - create_file_operation_prompt("copy-to:", cx, path, |_, copy_from, copy_to_str| { + create_file_operation_prompt("copy-to:", cx, path, |cx, copy_from, copy_to_str| { let copy_to = helix_stdx::path::expand_tilde(PathBuf::from(copy_to_str)); - if copy_from.is_dir() || copy_to_str.ends_with('/') { - // TODO: support copying directories (recursively)?. This isn't built-in to the standard library - Some(Err(format!( - "Copying directories is not supported: {} is a directory", copy_from.display() - ))) - } else if copy_to.exists() { - // TODO: confirmation prompt - Some(Err(format!("Path {} exists", copy_to.display()))) - } else { + + let copy_op = |copy_to_str: &str, copy_from: &Path| { + let copy_to = helix_stdx::path::expand_tilde(PathBuf::from(copy_to_str)); if let Err(err) = std::fs::copy(copy_from, ©_to).map_err( |err| format!("Unable to copy from file {} to {}: {err}", copy_from.display(), copy_to.display() @@ -493,6 +545,26 @@ pub fn file_explorer(root: PathBuf, editor: &Editor) -> Result