Skip to content

Commit ca78f4c

Browse files
authored
feat: add --empty and --cursor options to the rename command (#513)
1 parent 8533445 commit ca78f4c

File tree

4 files changed

+49
-9
lines changed

4 files changed

+49
-9
lines changed

Diff for: yazi-config/preset/keymap.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ keymap = [
7171
{ on = [ "d" ], exec = [ "remove", "escape --visual --select" ], desc = "Move the files to the trash" },
7272
{ on = [ "D" ], exec = [ "remove --permanently", "escape --visual --select" ], desc = "Permanently delete the files" },
7373
{ on = [ "a" ], exec = "create", desc = "Create a file or directory (ends with / for directories)" },
74-
{ on = [ "r" ], exec = "rename", desc = "Rename a file or directory" },
74+
{ on = [ "r" ], exec = "rename --cursor=before_ext", desc = "Rename a file or directory" },
7575
{ on = [ ";" ], exec = "shell", desc = "Run a shell command" },
7676
{ on = [ ":" ], exec = "shell --block", desc = "Run a shell command (block the UI until the command finishes)" },
7777
{ on = [ "." ], exec = "hidden toggle", desc = "Toggle the visibility of hidden files" },

Diff for: yazi-config/src/popup/options.rs

+7
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crate::{INPUT, SELECT};
55
pub struct InputCfg {
66
pub title: String,
77
pub value: String,
8+
pub cursor: Option<usize>,
89
pub position: Position,
910
pub realtime: bool,
1011
pub completion: bool,
@@ -130,6 +131,12 @@ impl InputCfg {
130131
self.value = value.into();
131132
self
132133
}
134+
135+
#[inline]
136+
pub fn with_cursor(mut self, cursor: Option<usize>) -> Self {
137+
self.cursor = cursor;
138+
self
139+
}
133140
}
134141

135142
impl SelectCfg {

Diff for: yazi-core/src/input/commands/show.rs

+6
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ impl Input {
4242

4343
// Reset snaps
4444
self.snaps.reset(opt.cfg.value, self.limit());
45+
46+
// Set cursor after reset
47+
if let Some(cursor) = opt.cfg.cursor {
48+
self.snaps.current_mut().cursor = cursor;
49+
}
50+
4551
render!();
4652
}
4753
}

Diff for: yazi-core/src/manager/commands/rename.rs

+35-8
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,37 @@ use yazi_shared::{event::Exec, fs::{max_common_root, File, FilesOp, Url}, term::
99

1010
use crate::{input::Input, manager::Manager};
1111

12-
pub struct Opt {
13-
force: bool,
12+
pub struct Opt<'a> {
13+
force: bool,
14+
empty: &'a str,
15+
cursor: &'a str,
1416
}
1517

16-
impl From<&Exec> for Opt {
17-
fn from(e: &Exec) -> Self { Self { force: e.named.contains_key("force") } }
18+
impl<'a> From<&'a Exec> for Opt<'a> {
19+
fn from(e: &'a Exec) -> Self {
20+
Self {
21+
force: e.named.contains_key("force"),
22+
empty: e.named.get("empty").map(|s| s.as_str()).unwrap_or_default(),
23+
cursor: e.named.get("cursor").map(|s| s.as_str()).unwrap_or_default(),
24+
}
25+
}
1826
}
1927

2028
impl Manager {
29+
fn empty_url_part(url: &Url, by: &str) -> String {
30+
if by == "all" {
31+
return String::new();
32+
}
33+
34+
let ext = url.extension();
35+
match by {
36+
"name" => ext.map_or_else(String::new, |s| format!(".{}", s.to_string_lossy().to_string())),
37+
"ext" if ext.is_some() => format!("{}.", url.file_stem().unwrap().to_string_lossy()),
38+
"dot_ext" if ext.is_some() => url.file_stem().unwrap().to_string_lossy().to_string(),
39+
_ => url.file_name().map_or_else(String::new, |s| s.to_string_lossy().to_string()),
40+
}
41+
}
42+
2143
async fn rename_and_hover(old: Url, new: Url) -> Result<()> {
2244
fs::rename(&old, &new).await?;
2345
if old.parent() != new.parent() {
@@ -29,7 +51,7 @@ impl Manager {
2951
Ok(Self::_hover(Some(new)))
3052
}
3153

32-
pub fn rename(&self, opt: impl Into<Opt>) {
54+
pub fn rename<'a>(&self, opt: impl Into<Opt<'a>>) {
3355
if self.active().in_selecting() {
3456
return self.bulk_rename();
3557
}
@@ -39,10 +61,15 @@ impl Manager {
3961
};
4062

4163
let opt = opt.into() as Opt;
42-
tokio::spawn(async move {
43-
let mut result =
44-
Input::_show(InputCfg::rename().with_value(hovered.file_name().unwrap().to_string_lossy()));
64+
let name = Self::empty_url_part(&hovered, opt.empty);
65+
let cursor = match opt.cursor {
66+
"start" => Some(0),
67+
"before_ext" => name.rfind('.').filter(|&n| n != 0),
68+
_ => None,
69+
};
4570

71+
tokio::spawn(async move {
72+
let mut result = Input::_show(InputCfg::rename().with_value(name).with_cursor(cursor));
4673
let Some(Ok(name)) = result.recv().await else {
4774
return;
4875
};

0 commit comments

Comments
 (0)