Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add rename command. #4514

Closed
wants to merge 15 commits into from
Closed
1 change: 1 addition & 0 deletions book/src/generated/typable-cmd.md
Original file line number Diff line number Diff line change
Expand Up @@ -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. |
Expand Down
48 changes: 47 additions & 1 deletion helix-term/src/commands/typed.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::ops::Deref;
use std::{ffi::OsStr, ops::Deref};

use crate::job::Job;

Expand Down Expand Up @@ -322,6 +322,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.");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There could be a :rename!/:rnm! version that skips this check so that renaming can overwrite existing files

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think we can add that too.

I will continue and add them in a separate PR.
WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@the-mikedavis Pls let me know if you have any questions on this.


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<str>],
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<str>],
Expand Down Expand Up @@ -1746,6 +1785,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"],
Expand Down