feat: add --empty and --cursor options to the rename command (#513)

This commit is contained in:
Azad 2024-01-15 17:14:49 +01:00 committed by GitHub
parent 85334457f3
commit ca78f4c9b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 49 additions and 9 deletions

View File

@ -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" },

View File

@ -5,6 +5,7 @@ use crate::{INPUT, SELECT};
pub struct InputCfg {
pub title: String,
pub value: String,
pub cursor: Option<usize>,
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<usize>) -> Self {
self.cursor = cursor;
self
}
}
impl SelectCfg {

View File

@ -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!();
}
}

View File

@ -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<Opt>) {
pub fn rename<'a>(&self, opt: impl Into<Opt<'a>>) {
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;
};