mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
feat: add --empty and --cursor options to the rename command (#513)
This commit is contained in:
parent
85334457f3
commit
ca78f4c9b0
4 changed files with 49 additions and 9 deletions
|
|
@ -71,7 +71,7 @@ keymap = [
|
||||||
{ on = [ "d" ], exec = [ "remove", "escape --visual --select" ], desc = "Move the files to the trash" },
|
{ 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 = [ "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 = [ "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", desc = "Run a shell command" },
|
||||||
{ on = [ ":" ], exec = "shell --block", desc = "Run a shell command (block the UI until the command finishes)" },
|
{ 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" },
|
{ on = [ "." ], exec = "hidden toggle", desc = "Toggle the visibility of hidden files" },
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ use crate::{INPUT, SELECT};
|
||||||
pub struct InputCfg {
|
pub struct InputCfg {
|
||||||
pub title: String,
|
pub title: String,
|
||||||
pub value: String,
|
pub value: String,
|
||||||
|
pub cursor: Option<usize>,
|
||||||
pub position: Position,
|
pub position: Position,
|
||||||
pub realtime: bool,
|
pub realtime: bool,
|
||||||
pub completion: bool,
|
pub completion: bool,
|
||||||
|
|
@ -130,6 +131,12 @@ impl InputCfg {
|
||||||
self.value = value.into();
|
self.value = value.into();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn with_cursor(mut self, cursor: Option<usize>) -> Self {
|
||||||
|
self.cursor = cursor;
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SelectCfg {
|
impl SelectCfg {
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,12 @@ impl Input {
|
||||||
|
|
||||||
// Reset snaps
|
// Reset snaps
|
||||||
self.snaps.reset(opt.cfg.value, self.limit());
|
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!();
|
render!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,15 +9,37 @@ use yazi_shared::{event::Exec, fs::{max_common_root, File, FilesOp, Url}, term::
|
||||||
|
|
||||||
use crate::{input::Input, manager::Manager};
|
use crate::{input::Input, manager::Manager};
|
||||||
|
|
||||||
pub struct Opt {
|
pub struct Opt<'a> {
|
||||||
force: bool,
|
force: bool,
|
||||||
|
empty: &'a str,
|
||||||
|
cursor: &'a str,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&Exec> for Opt {
|
impl<'a> From<&'a Exec> for Opt<'a> {
|
||||||
fn from(e: &Exec) -> Self { Self { force: e.named.contains_key("force") } }
|
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 {
|
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<()> {
|
async fn rename_and_hover(old: Url, new: Url) -> Result<()> {
|
||||||
fs::rename(&old, &new).await?;
|
fs::rename(&old, &new).await?;
|
||||||
if old.parent() != new.parent() {
|
if old.parent() != new.parent() {
|
||||||
|
|
@ -29,7 +51,7 @@ impl Manager {
|
||||||
Ok(Self::_hover(Some(new)))
|
Ok(Self::_hover(Some(new)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rename(&self, opt: impl Into<Opt>) {
|
pub fn rename<'a>(&self, opt: impl Into<Opt<'a>>) {
|
||||||
if self.active().in_selecting() {
|
if self.active().in_selecting() {
|
||||||
return self.bulk_rename();
|
return self.bulk_rename();
|
||||||
}
|
}
|
||||||
|
|
@ -39,10 +61,15 @@ impl Manager {
|
||||||
};
|
};
|
||||||
|
|
||||||
let opt = opt.into() as Opt;
|
let opt = opt.into() as Opt;
|
||||||
tokio::spawn(async move {
|
let name = Self::empty_url_part(&hovered, opt.empty);
|
||||||
let mut result =
|
let cursor = match opt.cursor {
|
||||||
Input::_show(InputCfg::rename().with_value(hovered.file_name().unwrap().to_string_lossy()));
|
"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 {
|
let Some(Ok(name)) = result.recv().await else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue