From de898460b812a094df0c0ab3b1eb8f8ff3aba7ff Mon Sep 17 00:00:00 2001 From: belowm Date: Thu, 10 Jul 2025 21:28:53 +0200 Subject: [PATCH] Allow `:move` command to accept directories as target (#13922) Co-authored-by: Martin Below --- helix-term/src/commands/typed.rs | 11 +++- helix-term/tests/test/commands/write.rs | 67 +++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index e1bb8ee32..c487e7916 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -2463,7 +2463,16 @@ fn move_buffer(cx: &mut compositor::Context, args: Args, event: PromptEvent) -> .path() .context("Scratch buffer cannot be moved. Use :write instead")? .clone(); - let new_path = args.first().unwrap().to_string(); + let new_path: PathBuf = args.first().unwrap().into(); + + // if new_path is a directory, append the original file name + // to move the file into that directory. + let new_path = old_path + .file_name() + .filter(|_| new_path.is_dir()) + .map(|old_file_name| new_path.join(old_file_name)) + .unwrap_or(new_path); + if let Err(err) = cx.editor.move_path(&old_path, new_path.as_ref()) { bail!("Could not move file: {err}"); } diff --git a/helix-term/tests/test/commands/write.rs b/helix-term/tests/test/commands/write.rs index 4b78e14c4..0cf09e1ea 100644 --- a/helix-term/tests/test/commands/write.rs +++ b/helix-term/tests/test/commands/write.rs @@ -772,3 +772,70 @@ async fn edit_file_with_content(file_content: &[u8]) -> anyhow::Result<()> { Ok(()) } + +#[tokio::test(flavor = "multi_thread")] +async fn test_move_file_when_given_dir_and_filename() -> anyhow::Result<()> { + let dir = tempfile::tempdir()?; + let source_file = tempfile::NamedTempFile::new_in(&dir)?; + let target_file = dir.path().join("new_name.ext"); + + let mut app = helpers::AppBuilder::new() + .with_file(source_file.path(), None) + .build()?; + + test_key_sequence( + &mut app, + Some(format!(":move {}", target_file.to_string_lossy()).as_ref()), + None, + false, + ) + .await?; + + assert!( + target_file.is_file(), + "target file '{}' should have been created", + target_file.display() + ); + assert!( + !source_file.path().exists(), + "Source file '{}' should have been removed", + source_file.path().display() + ); + + Ok(()) +} + +#[tokio::test(flavor = "multi_thread")] +async fn test_move_file_when_given_dir_only() -> anyhow::Result<()> { + let source_dir = tempfile::tempdir()?; + let target_dir = tempfile::tempdir()?; + let source_file = source_dir.path().join("file.ext"); + std::fs::File::create(&source_file)?; + + let mut app = helpers::AppBuilder::new() + .with_file(&source_file, None) + .build()?; + + test_key_sequence( + &mut app, + Some(format!(":move {}", target_dir.path().to_string_lossy()).as_ref()), + None, + false, + ) + .await?; + + let target_file = target_dir.path().join("file.ext"); + + assert!( + target_file.is_file(), + "target file '{}' should have been created", + target_file.display() + ); + assert!( + !source_file.exists(), + "Source file '{}' should have been removed", + source_file.display() + ); + + Ok(()) +}