diff --git a/book/src/generated/typable-cmd.md b/book/src/generated/typable-cmd.md index ab36997c7016..5eb31e0e9db7 100644 --- a/book/src/generated/typable-cmd.md +++ b/book/src/generated/typable-cmd.md @@ -11,6 +11,7 @@ | `:buffer-close-all!`, `:bca!`, `:bcloseall!` | Force close all buffers ignoring unsaved changes without quitting. | | `:buffer-next`, `:bn`, `:bnext` | Goto next buffer. | | `:buffer-previous`, `:bp`, `:bprev` | Goto previous buffer. | +| `:rename`, `:rnm` | Rename file. Accepts a file name arg (:rename new_name.txt) | | `:write`, `:w` | Write changes to disk. Accepts an optional path (:write some/path.txt) | | `:write!`, `:w!` | Force write changes to disk creating necessary subdirectories. Accepts an optional path (:write some/path.txt) | | `:new`, `:n` | Create a new scratch buffer. | diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index b0fd18a76b79..73e45a162dfb 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -1,3 +1,4 @@ +use std::ffi::OsStr; use std::fmt::Write; use std::ops::Deref; @@ -340,6 +341,45 @@ fn force_write( write_impl(cx, args.first(), true) } +fn rename_impl(cx: &mut compositor::Context, new_name: &str) -> anyhow::Result<()> { + let (_view, doc) = current!(cx.editor); + + let path = if let Some(path) = doc.relative_path() { + path + } else { + bail!("File must exist to rename."); + }; + + let mut new_path = path.clone(); + new_path.set_file_name(OsStr::new(new_name)); + + ensure!( + new_path.parent() == path.parent(), + "Root path must be the same." + ); + + ensure!(!new_path.exists(), "File already exists."); + + std::fs::rename(path, new_path.as_path())?; + doc.set_path(Some(new_path.as_path()))?; + + Ok(()) +} + +fn rename( + cx: &mut compositor::Context, + args: &[Cow], + event: PromptEvent, +) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + } + + ensure!(args.len() == 1, "Bad arguments. Usage: `:rename new_name`"); + + rename_impl(cx, args.first().unwrap()) +} + fn new_file( cx: &mut compositor::Context, _args: &[Cow], @@ -2080,6 +2120,13 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ fun: buffer_previous, completer: None, }, + TypableCommand { + name: "rename", + aliases: &["rnm"], + doc: "Rename file. Accepts a file name arg (:rename new_name.txt)", + fun: rename, + completer: Some(completers::filename), + }, TypableCommand { name: "write", aliases: &["w"],