mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
refactor: using fixed patterns to simplify keybindings
This commit is contained in:
parent
53525b511e
commit
c7cc29e6b0
14 changed files with 121 additions and 80 deletions
|
|
@ -58,29 +58,29 @@ keymap = [
|
|||
{ on = [ "<C-r>" ], 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 = [ "<Enter>" ], exec = [ "escape --visual", "open" ], desc = "Open the selected files" },
|
||||
{ on = [ "<C-Enter>" ], 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 = [ "<C-s>" ], 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 = [ "<Enter>" ], exec = "open", desc = "Open the selected files" },
|
||||
{ on = [ "<C-Enter>" ], 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 = [ "<C-s>" ], 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" },
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -25,8 +25,11 @@ impl From<Cmd> for Opt {
|
|||
|
||||
impl Manager {
|
||||
pub fn open(&mut self, opt: impl Into<Opt>, 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 {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,10 @@ impl From<Cmd> for Opt {
|
|||
|
||||
impl Manager {
|
||||
pub fn remove(&mut self, opt: impl Into<Opt>, 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);
|
||||
|
|
|
|||
|
|
@ -52,8 +52,10 @@ impl Manager {
|
|||
Ok(Self::_hover(Some(new)))
|
||||
}
|
||||
|
||||
pub fn rename(&self, opt: impl Into<Opt>) {
|
||||
if !self.active().selected.is_empty() {
|
||||
pub fn rename(&mut self, opt: impl Into<Opt>) {
|
||||
if !self.active_mut().try_escape_visual() {
|
||||
return;
|
||||
} else if !self.active().selected.is_empty() {
|
||||
return self.bulk_rename();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,10 @@ impl From<Cmd> for Opt {
|
|||
|
||||
impl Manager {
|
||||
pub fn yank(&mut self, opt: impl Into<Opt>) {
|
||||
if !self.active_mut().try_escape_visual() {
|
||||
return;
|
||||
}
|
||||
|
||||
let selected: HashSet<_> = self.selected_or_hovered().into_iter().cloned().collect();
|
||||
if selected.is_empty() {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -13,8 +13,11 @@ impl From<Cmd> for Opt {
|
|||
}
|
||||
|
||||
impl Tab {
|
||||
pub fn copy(&self, opt: impl Into<Opt>) {
|
||||
pub fn copy(&mut self, opt: impl Into<Opt>) {
|
||||
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();
|
||||
|
|
|
|||
|
|
@ -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<Cmd> for Opt {
|
|||
}
|
||||
|
||||
impl Tab {
|
||||
pub fn escape(&mut self, opt: impl Into<Opt>) {
|
||||
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<Opt>) {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,11 @@ impl From<Cmd> for Opt {
|
|||
}
|
||||
|
||||
impl Tab {
|
||||
pub fn shell(&self, opt: impl Into<Opt>) {
|
||||
pub fn shell(&mut self, opt: impl Into<Opt>) {
|
||||
if !self.try_escape_visual() {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut opt = opt.into() as Opt;
|
||||
let selected: Vec<_> = self.selected_or_hovered().into_iter().cloned().collect();
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue