From ca78f4c9b089f38ea0363b29bcc1f75ab32b5a3f Mon Sep 17 00:00:00 2001 From: Azad <49314270+Akmadan23@users.noreply.github.com> Date: Mon, 15 Jan 2024 17:14:49 +0100 Subject: [PATCH] feat: add `--empty` and `--cursor` options to the `rename` command (#513) --- yazi-config/preset/keymap.toml | 2 +- yazi-config/src/popup/options.rs | 7 ++++ yazi-core/src/input/commands/show.rs | 6 ++++ yazi-core/src/manager/commands/rename.rs | 43 +++++++++++++++++++----- 4 files changed, 49 insertions(+), 9 deletions(-) diff --git a/yazi-config/preset/keymap.toml b/yazi-config/preset/keymap.toml index a464e73e..3e2aac05 100644 --- a/yazi-config/preset/keymap.toml +++ b/yazi-config/preset/keymap.toml @@ -71,7 +71,7 @@ keymap = [ { on = [ "d" ], exec = [ "remove", "escape --visual --select" ], desc = "Move the files to the trash" }, { on = [ "D" ], exec = [ "remove --permanently", "escape --visual --select" ], desc = "Permanently delete the files" }, { on = [ "a" ], exec = "create", desc = "Create a file or directory (ends with / for directories)" }, - { on = [ "r" ], exec = "rename", desc = "Rename a file or directory" }, + { on = [ "r" ], exec = "rename --cursor=before_ext", desc = "Rename a file or directory" }, { on = [ ";" ], exec = "shell", desc = "Run a shell command" }, { on = [ ":" ], exec = "shell --block", desc = "Run a shell command (block the UI until the command finishes)" }, { on = [ "." ], exec = "hidden toggle", desc = "Toggle the visibility of hidden files" }, diff --git a/yazi-config/src/popup/options.rs b/yazi-config/src/popup/options.rs index 9ef592e4..21b2c108 100644 --- a/yazi-config/src/popup/options.rs +++ b/yazi-config/src/popup/options.rs @@ -5,6 +5,7 @@ use crate::{INPUT, SELECT}; pub struct InputCfg { pub title: String, pub value: String, + pub cursor: Option, pub position: Position, pub realtime: bool, pub completion: bool, @@ -130,6 +131,12 @@ impl InputCfg { self.value = value.into(); self } + + #[inline] + pub fn with_cursor(mut self, cursor: Option) -> Self { + self.cursor = cursor; + self + } } impl SelectCfg { diff --git a/yazi-core/src/input/commands/show.rs b/yazi-core/src/input/commands/show.rs index 0ff6aa3a..cdb3b87b 100644 --- a/yazi-core/src/input/commands/show.rs +++ b/yazi-core/src/input/commands/show.rs @@ -42,6 +42,12 @@ impl Input { // Reset snaps self.snaps.reset(opt.cfg.value, self.limit()); + + // Set cursor after reset + if let Some(cursor) = opt.cfg.cursor { + self.snaps.current_mut().cursor = cursor; + } + render!(); } } diff --git a/yazi-core/src/manager/commands/rename.rs b/yazi-core/src/manager/commands/rename.rs index 632e6092..fd517127 100644 --- a/yazi-core/src/manager/commands/rename.rs +++ b/yazi-core/src/manager/commands/rename.rs @@ -9,15 +9,37 @@ use yazi_shared::{event::Exec, fs::{max_common_root, File, FilesOp, Url}, term:: use crate::{input::Input, manager::Manager}; -pub struct Opt { - force: bool, +pub struct Opt<'a> { + force: bool, + empty: &'a str, + cursor: &'a str, } -impl From<&Exec> for Opt { - fn from(e: &Exec) -> Self { Self { force: e.named.contains_key("force") } } +impl<'a> From<&'a Exec> for Opt<'a> { + fn from(e: &'a Exec) -> Self { + Self { + force: e.named.contains_key("force"), + empty: e.named.get("empty").map(|s| s.as_str()).unwrap_or_default(), + cursor: e.named.get("cursor").map(|s| s.as_str()).unwrap_or_default(), + } + } } impl Manager { + fn empty_url_part(url: &Url, by: &str) -> String { + if by == "all" { + return String::new(); + } + + let ext = url.extension(); + match by { + "name" => ext.map_or_else(String::new, |s| format!(".{}", s.to_string_lossy().to_string())), + "ext" if ext.is_some() => format!("{}.", url.file_stem().unwrap().to_string_lossy()), + "dot_ext" if ext.is_some() => url.file_stem().unwrap().to_string_lossy().to_string(), + _ => url.file_name().map_or_else(String::new, |s| s.to_string_lossy().to_string()), + } + } + async fn rename_and_hover(old: Url, new: Url) -> Result<()> { fs::rename(&old, &new).await?; if old.parent() != new.parent() { @@ -29,7 +51,7 @@ impl Manager { Ok(Self::_hover(Some(new))) } - pub fn rename(&self, opt: impl Into) { + pub fn rename<'a>(&self, opt: impl Into>) { if self.active().in_selecting() { return self.bulk_rename(); } @@ -39,10 +61,15 @@ impl Manager { }; let opt = opt.into() as Opt; - tokio::spawn(async move { - let mut result = - Input::_show(InputCfg::rename().with_value(hovered.file_name().unwrap().to_string_lossy())); + let name = Self::empty_url_part(&hovered, opt.empty); + let cursor = match opt.cursor { + "start" => Some(0), + "before_ext" => name.rfind('.').filter(|&n| n != 0), + _ => None, + }; + tokio::spawn(async move { + let mut result = Input::_show(InputCfg::rename().with_value(name).with_cursor(cursor)); let Some(Ok(name)) = result.recv().await else { return; };