From c7cc29e6b0dbc8f0dbff5bf6aa07f251704682bd Mon Sep 17 00:00:00 2001 From: sxyazi Date: Sat, 17 Feb 2024 16:49:44 +0800 Subject: [PATCH] refactor: using fixed patterns to simplify keybindings --- yazi-config/preset/keymap.toml | 54 ++++++++-------- yazi-config/src/theme/theme.rs | 2 +- yazi-core/src/help/help.rs | 5 +- yazi-core/src/manager/commands/open.rs | 5 +- yazi-core/src/manager/commands/remove.rs | 4 ++ yazi-core/src/manager/commands/rename.rs | 6 +- yazi-core/src/manager/commands/yank.rs | 4 ++ yazi-core/src/tab/commands/copy.rs | 5 +- yazi-core/src/tab/commands/escape.rs | 82 +++++++++++++----------- yazi-core/src/tab/commands/find.rs | 3 +- yazi-core/src/tab/commands/shell.rs | 6 +- yazi-core/src/which/which.rs | 5 +- yazi-plugin/preset/components/header.lua | 4 +- yazi-shared/src/event/render.rs | 16 ++++- 14 files changed, 121 insertions(+), 80 deletions(-) diff --git a/yazi-config/preset/keymap.toml b/yazi-config/preset/keymap.toml index 5ae3867d..f90d4d89 100644 --- a/yazi-config/preset/keymap.toml +++ b/yazi-config/preset/keymap.toml @@ -58,29 +58,29 @@ keymap = [ { on = [ "" ], exec = "select_all --state=none", desc = "Inverse selection of all files" }, # Operation - { on = [ "o" ], exec = [ "escape --visual", "open" ], desc = "Open the selected files" }, - { on = [ "O" ], exec = [ "escape --visual", "open --interactive" ], desc = "Open the selected files interactively" }, - { on = [ "" ], exec = [ "escape --visual", "open" ], desc = "Open the selected files" }, - { on = [ "" ], exec = [ "escape --visual", "open --interactive" ], desc = "Open the selected files interactively" }, - { on = [ "y" ], exec = [ "escape --visual", "yank" ], desc = "Copy the selected files" }, - { on = [ "Y" ], exec = "unyank", desc = "Cancel the yank status of files" }, - { on = [ "x" ], exec = [ "escape --visual", "yank --cut" ], desc = "Cut the selected files" }, - { on = [ "p" ], exec = "paste", desc = "Paste the files" }, - { on = [ "P" ], exec = "paste --force", desc = "Paste the files (overwrite if the destination exists)" }, - { on = [ "-" ], exec = "link", desc = "Symlink the absolute path of files" }, - { on = [ "_" ], exec = "link --relative", desc = "Symlink the relative path of files" }, - { on = [ "d" ], exec = [ "escape --visual", "remove" ], desc = "Move the files to the trash" }, - { on = [ "D" ], exec = [ "escape --visual", "remove --permanently" ], desc = "Permanently delete the files" }, - { on = [ "a" ], exec = "create", desc = "Create a file or directory (ends with / for directories)" }, - { on = [ "r" ], exec = [ "escape --visual", "rename --cursor=before_ext" ], desc = "Rename a file or directory" }, - { on = [ ";" ], exec = [ "escape --visual", "shell" ], desc = "Run a shell command" }, - { on = [ ":" ], exec = [ "escape --visual", "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 = [ "s" ], exec = "search fd", desc = "Search files by name using fd" }, - { on = [ "S" ], exec = "search rg", desc = "Search files by content using ripgrep" }, - { on = [ "" ], exec = "search none", desc = "Cancel the ongoing search" }, - { on = [ "z" ], exec = "jump zoxide", desc = "Jump to a directory using zoxide" }, - { on = [ "Z" ], exec = "jump fzf", desc = "Jump to a directory, or reveal a file using fzf" }, + { on = [ "o" ], exec = "open", desc = "Open the selected files" }, + { on = [ "O" ], exec = "open --interactive", desc = "Open the selected files interactively" }, + { on = [ "" ], exec = "open", desc = "Open the selected files" }, + { on = [ "" ], exec = "open --interactive", desc = "Open the selected files interactively" }, + { on = [ "y" ], exec = "yank", desc = "Copy the selected files" }, + { on = [ "Y" ], exec = "unyank", desc = "Cancel the yank status of files" }, + { on = [ "x" ], exec = "yank --cut", desc = "Cut the selected files" }, + { on = [ "p" ], exec = "paste", desc = "Paste the files" }, + { on = [ "P" ], exec = "paste --force", desc = "Paste the files (overwrite if the destination exists)" }, + { on = [ "-" ], exec = "link", desc = "Symlink the absolute path of files" }, + { on = [ "_" ], exec = "link --relative", desc = "Symlink the relative path of files" }, + { on = [ "d" ], exec = "remove", desc = "Move the files to the trash" }, + { on = [ "D" ], exec = "remove --permanently", desc = "Permanently delete the files" }, + { on = [ "a" ], exec = "create", desc = "Create a file or directory (ends with / for directories)" }, + { 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" }, + { on = [ "s" ], exec = "search fd", desc = "Search files by name using fd" }, + { on = [ "S" ], exec = "search rg", desc = "Search files by content using ripgrep" }, + { on = [ "" ], exec = "search none", desc = "Cancel the ongoing search" }, + { on = [ "z" ], exec = "jump zoxide", desc = "Jump to a directory using zoxide" }, + { on = [ "Z" ], exec = "jump fzf", desc = "Jump to a directory, or reveal a file using fzf" }, # Linemode { on = [ "m", "s" ], exec = "linemode size", desc = "Set linemode to size" }, @@ -89,10 +89,10 @@ keymap = [ { on = [ "m", "n" ], exec = "linemode none", desc = "Set linemode to none" }, # Copy - { on = [ "c", "c" ], exec = [ "escape --visual", "copy path" ], desc = "Copy the absolute path" }, - { on = [ "c", "d" ], exec = [ "escape --visual", "copy dirname" ], desc = "Copy the path of the parent directory" }, - { on = [ "c", "f" ], exec = [ "escape --visual", "copy filename" ], desc = "Copy the name of the file" }, - { on = [ "c", "n" ], exec = [ "escape --visual", "copy name_without_ext" ], desc = "Copy the name of the file without the extension" }, + { on = [ "c", "c" ], exec = "copy path", desc = "Copy the absolute path" }, + { on = [ "c", "d" ], exec = "copy dirname", desc = "Copy the path of the parent directory" }, + { on = [ "c", "f" ], exec = "copy filename", desc = "Copy the name of the file" }, + { on = [ "c", "n" ], exec = "copy name_without_ext", desc = "Copy the name of the file without the extension" }, # Filter { on = [ "f" ], exec = "filter --smart", desc = "Filter the files" }, diff --git a/yazi-config/src/theme/theme.rs b/yazi-config/src/theme/theme.rs index 66d6e479..0ca24bea 100644 --- a/yazi-config/src/theme/theme.rs +++ b/yazi-config/src/theme/theme.rs @@ -31,7 +31,7 @@ pub struct Manager { #[validate(range(min = 1, message = "Must be greater than 0"))] tab_width: u8, - // Selected counter + // Count count_selected: Style, count_copied: Style, count_cut: Style, diff --git a/yazi-core/src/help/help.rs b/yazi-core/src/help/help.rs index 0126c155..f2898945 100644 --- a/yazi-core/src/help/help.rs +++ b/yazi-core/src/help/help.rs @@ -1,7 +1,7 @@ use crossterm::event::KeyCode; use unicode_width::UnicodeWidthStr; use yazi_config::{keymap::{Control, Key}, KEYMAP}; -use yazi_shared::{render, term::Term, Layer}; +use yazi_shared::{render, render_and, term::Term, Layer}; use super::HELP_MARGIN; use crate::input::Input; @@ -49,8 +49,7 @@ impl Help { } Key { code: KeyCode::Enter, shift: false, ctrl: false, alt: false } => { self.in_filter = None; - render!(); - return true; // Don't do the `filter_apply` below, since we already have the filtered results. + return render_and!(true); // Don't do the `filter_apply` below, since we already have the filtered results. } Key { code: KeyCode::Backspace, shift: false, ctrl: false, alt: false } => { input.backspace(false); diff --git a/yazi-core/src/manager/commands/open.rs b/yazi-core/src/manager/commands/open.rs index 73e10325..9e697774 100644 --- a/yazi-core/src/manager/commands/open.rs +++ b/yazi-core/src/manager/commands/open.rs @@ -25,8 +25,11 @@ impl From for Opt { impl Manager { pub fn open(&mut self, opt: impl Into, tasks: &Tasks) { - let mut opt = opt.into() as Opt; + if !self.active_mut().try_escape_visual() { + return; + } + let mut opt = opt.into() as Opt; let selected = if opt.hovered { self.hovered().map(|h| vec![&h.url]).unwrap_or_default() } else { diff --git a/yazi-core/src/manager/commands/remove.rs b/yazi-core/src/manager/commands/remove.rs index 15e9f70e..9352b996 100644 --- a/yazi-core/src/manager/commands/remove.rs +++ b/yazi-core/src/manager/commands/remove.rs @@ -18,6 +18,10 @@ impl From for Opt { impl Manager { pub fn remove(&mut self, opt: impl Into, tasks: &Tasks) { + if !self.active_mut().try_escape_visual() { + return; + } + let opt = opt.into() as Opt; let targets = self.selected_or_hovered().into_iter().cloned().collect(); tasks.file_remove(targets, opt.force, opt.permanently); diff --git a/yazi-core/src/manager/commands/rename.rs b/yazi-core/src/manager/commands/rename.rs index 80271fd2..3164b40b 100644 --- a/yazi-core/src/manager/commands/rename.rs +++ b/yazi-core/src/manager/commands/rename.rs @@ -52,8 +52,10 @@ impl Manager { Ok(Self::_hover(Some(new))) } - pub fn rename(&self, opt: impl Into) { - if !self.active().selected.is_empty() { + pub fn rename(&mut self, opt: impl Into) { + if !self.active_mut().try_escape_visual() { + return; + } else if !self.active().selected.is_empty() { return self.bulk_rename(); } diff --git a/yazi-core/src/manager/commands/yank.rs b/yazi-core/src/manager/commands/yank.rs index ab5dee17..5383382d 100644 --- a/yazi-core/src/manager/commands/yank.rs +++ b/yazi-core/src/manager/commands/yank.rs @@ -14,6 +14,10 @@ impl From for Opt { impl Manager { pub fn yank(&mut self, opt: impl Into) { + if !self.active_mut().try_escape_visual() { + return; + } + let selected: HashSet<_> = self.selected_or_hovered().into_iter().cloned().collect(); if selected.is_empty() { return; diff --git a/yazi-core/src/tab/commands/copy.rs b/yazi-core/src/tab/commands/copy.rs index 78477bb6..8e47ea24 100644 --- a/yazi-core/src/tab/commands/copy.rs +++ b/yazi-core/src/tab/commands/copy.rs @@ -13,8 +13,11 @@ impl From for Opt { } impl Tab { - pub fn copy(&self, opt: impl Into) { + pub fn copy(&mut self, opt: impl Into) { let opt = opt.into() as Opt; + if !self.try_escape_visual() { + return; + } let mut s = OsString::new(); let mut it = self.selected_or_hovered().into_iter().peekable(); diff --git a/yazi-core/src/tab/commands/escape.rs b/yazi-core/src/tab/commands/escape.rs index d30b0b26..5f6ffcc0 100644 --- a/yazi-core/src/tab/commands/escape.rs +++ b/yazi-core/src/tab/commands/escape.rs @@ -1,5 +1,5 @@ use bitflags::bitflags; -use yazi_shared::{event::Cmd, render}; +use yazi_shared::{event::Cmd, render, render_and}; use crate::{manager::Manager, tab::{Mode, Tab}}; @@ -28,8 +28,36 @@ impl From for Opt { } impl Tab { + pub fn escape(&mut self, opt: impl Into) { + let opt = opt.into() as Opt; + if opt.is_empty() { + _ = self.escape_find() + || self.escape_visual() + || self.escape_select() + || self.escape_filter() + || self.escape_search(); + return; + } + + if opt.contains(Opt::FIND) { + self.escape_find(); + } + if opt.contains(Opt::VISUAL) { + self.escape_visual(); + } + if opt.contains(Opt::SELECT) { + self.escape_select(); + } + if opt.contains(Opt::FILTER) { + self.escape_filter(); + } + if opt.contains(Opt::SEARCH) { + self.escape_search(); + } + } + #[inline] - pub fn escape_find(&mut self) -> bool { self.finder.take().is_some() } + pub fn escape_find(&mut self) -> bool { render_and!(self.finder.take().is_some()) } #[inline] pub fn escape_visual(&mut self) -> bool { @@ -47,8 +75,7 @@ impl Tab { } self.mode = Mode::Normal; - render!(); - true + render_and!(true) } #[inline] @@ -61,49 +88,32 @@ impl Tab { if self.current.hovered().is_some_and(|h| h.is_dir()) { Manager::_peek(true); } - true + render_and!(true) } #[inline] pub fn escape_filter(&mut self) -> bool { - let b = self.current.files.filter().is_some(); + if self.current.files.filter().is_none() { + return false; + } + self.filter_do(super::filter::Opt::default()); - b + render_and!(true) } #[inline] pub fn escape_search(&mut self) -> bool { - let b = self.current.cwd.is_search(); + if !self.current.cwd.is_search() { + return false; + } + self.search_stop(); - b + render_and!(true) } - pub fn escape(&mut self, opt: impl Into) { - let opt = opt.into() as Opt; - if opt.is_empty() { - return render!( - self.escape_find() - || self.escape_visual() - || self.escape_select() - || self.escape_filter() - || self.escape_search() - ); - } - - if opt.contains(Opt::FIND) { - render!(self.escape_find()); - } - if opt.contains(Opt::VISUAL) { - render!(self.escape_visual()); - } - if opt.contains(Opt::SELECT) { - render!(self.escape_select()); - } - if opt.contains(Opt::FILTER) { - render!(self.escape_filter()); - } - if opt.contains(Opt::SEARCH) { - render!(self.escape_search()); - } + #[inline] + pub fn try_escape_visual(&mut self) -> bool { + self.escape_visual(); + true } } diff --git a/yazi-core/src/tab/commands/find.rs b/yazi-core/src/tab/commands/find.rs index 7da0fc27..a506d558 100644 --- a/yazi-core/src/tab/commands/find.rs +++ b/yazi-core/src/tab/commands/find.rs @@ -58,7 +58,8 @@ impl Tab { return; }; if query.is_empty() { - return self.escape(super::escape::Opt::FIND); + self.escape_find(); + return; } let Ok(finder) = Finder::new(&query, opt.case) else { diff --git a/yazi-core/src/tab/commands/shell.rs b/yazi-core/src/tab/commands/shell.rs index 11c07983..a74ca0f0 100644 --- a/yazi-core/src/tab/commands/shell.rs +++ b/yazi-core/src/tab/commands/shell.rs @@ -20,7 +20,11 @@ impl From for Opt { } impl Tab { - pub fn shell(&self, opt: impl Into) { + pub fn shell(&mut self, opt: impl Into) { + if !self.try_escape_visual() { + return; + } + let mut opt = opt.into() as Opt; let selected: Vec<_> = self.selected_or_hovered().into_iter().cloned().collect(); diff --git a/yazi-core/src/which/which.rs b/yazi-core/src/which/which.rs index d6227775..7791263d 100644 --- a/yazi-core/src/which/which.rs +++ b/yazi-core/src/which/which.rs @@ -1,5 +1,5 @@ use yazi_config::keymap::{ControlCow, Key}; -use yazi_shared::{emit, render, Layer}; +use yazi_shared::{emit, render, render_and, Layer}; #[derive(Default)] pub struct Which { @@ -27,8 +27,7 @@ impl Which { self.reset(); } - render!(); - true + render_and!(true) } fn reset(&mut self) { diff --git a/yazi-plugin/preset/components/header.lua b/yazi-plugin/preset/components/header.lua index 1cfc1d17..f0f84bf4 100644 --- a/yazi-plugin/preset/components/header.lua +++ b/yazi-plugin/preset/components/header.lua @@ -14,7 +14,7 @@ function Header:cwd() return span:style(THEME.manager.cwd) end -function Header:counter() +function Header:count() local yanked = #cx.yanked local count, style @@ -73,7 +73,7 @@ function Header:render(area) local chunks = self:layout(area) local left = ui.Line { self:cwd() } - local right = ui.Line { self:counter(), self:tabs() } + local right = ui.Line { self:count(), self:tabs() } return { ui.Paragraph(chunks[1], { left }), ui.Paragraph(chunks[2], { right }):align(ui.Paragraph.RIGHT), diff --git a/yazi-shared/src/event/render.rs b/yazi-shared/src/event/render.rs index c616f9c5..5fa8fe5a 100644 --- a/yazi-shared/src/event/render.rs +++ b/yazi-shared/src/event/render.rs @@ -7,9 +7,21 @@ macro_rules! render { () => { $crate::event::NEED_RENDER.store(true, std::sync::atomic::Ordering::Relaxed); }; - ($expr:expr) => { - if $expr { + ($cond:expr) => { + if $cond { render!(); } }; } + +#[macro_export] +macro_rules! render_and { + ($cond:expr) => { + if $cond { + render!(); + true + } else { + false + } + }; +}