From 50b7f1af2b41df6e1297e6592e674a975f69254d Mon Sep 17 00:00:00 2001 From: sxyazi Date: Thu, 2 Nov 2023 19:02:12 +0800 Subject: [PATCH] WIP [no ci] --- yazi-config/src/keymap/key.rs | 2 +- yazi-core/src/completion/commands/trigger.rs | 1 - yazi-core/src/context.rs | 21 +- yazi-fm/src/app.rs | 6 +- yazi-fm/src/executor.rs | 280 +++++++++++-------- 5 files changed, 161 insertions(+), 149 deletions(-) diff --git a/yazi-config/src/keymap/key.rs b/yazi-config/src/keymap/key.rs index 7e59b33c..a5f56e96 100644 --- a/yazi-config/src/keymap/key.rs +++ b/yazi-config/src/keymap/key.rs @@ -2,7 +2,7 @@ use anyhow::bail; use crossterm::event::{KeyCode, KeyEvent, KeyModifiers}; use serde::Deserialize; -#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq, Hash)] #[serde(try_from = "String")] pub struct Key { pub code: KeyCode, diff --git a/yazi-core/src/completion/commands/trigger.rs b/yazi-core/src/completion/commands/trigger.rs index 38fdb7ab..0c442811 100644 --- a/yazi-core/src/completion/commands/trigger.rs +++ b/yazi-core/src/completion/commands/trigger.rs @@ -1,5 +1,4 @@ use tokio::fs; -use tracing::info; use yazi_config::keymap::{Exec, KeymapLayer}; use crate::{completion::Completion, emit}; diff --git a/yazi-core/src/context.rs b/yazi-core/src/context.rs index 12a056c8..08b3206a 100644 --- a/yazi-core/src/context.rs +++ b/yazi-core/src/context.rs @@ -70,27 +70,8 @@ impl Ctx { None } - #[inline] - pub fn layer(&self) -> KeymapLayer { - if self.which.visible { - KeymapLayer::Which - } else if self.completion.visible { - KeymapLayer::Completion - } else if self.help.visible { - KeymapLayer::Help - } else if self.input.visible { - KeymapLayer::Input - } else if self.select.visible { - KeymapLayer::Select - } else if self.tasks.visible { - KeymapLayer::Tasks - } else { - KeymapLayer::Manager - } - } - #[inline] pub fn image_layer(&self) -> bool { - !matches!(self.layer(), KeymapLayer::Which | KeymapLayer::Help | KeymapLayer::Tasks) + !self.which.visible && !self.help.visible && !self.tasks.visible } } diff --git a/yazi-fm/src/app.rs b/yazi-fm/src/app.rs index ddf43c8b..3a83a297 100644 --- a/yazi-fm/src/app.rs +++ b/yazi-fm/src/app.rs @@ -59,13 +59,13 @@ impl App { fn dispatch_key(&mut self, key: KeyEvent) { let key = Key::from(key); - if Executor::handle(&mut self.cx, key) { + if Executor::new(&mut self.cx).handle(key) { emit!(Render); } } fn dispatch_paste(&mut self, str: String) { - if self.cx.layer() == KeymapLayer::Input { + if self.cx.input.visible { let input = &mut self.cx.input; if input.mode() == InputMode::Insert && input.type_str(&str) { emit!(Render); @@ -112,7 +112,7 @@ impl App { #[inline] fn dispatch_call(&mut self, exec: Vec, layer: KeymapLayer) { - if Executor::dispatch(&mut self.cx, &exec, layer) { + if Executor::new(&mut self.cx).dispatch(&exec, layer) { emit!(Render); } } diff --git a/yazi-fm/src/executor.rs b/yazi-fm/src/executor.rs index fa6fcc1e..8133a192 100644 --- a/yazi-fm/src/executor.rs +++ b/yazi-fm/src/executor.rs @@ -2,79 +2,99 @@ use yazi_config::{keymap::{Control, Exec, Key, KeymapLayer}, KEYMAP}; use yazi_core::{emit, input::InputMode, tab::FinderCase, Ctx}; use yazi_shared::{optional_bool, Url}; -pub(super) struct Executor; +pub(super) struct Executor<'a> { + cx: &'a mut Ctx, +} -impl Executor { - pub(super) fn handle(cx: &mut Ctx, key: Key) -> bool { - let layer = cx.layer(); - if layer == KeymapLayer::Which { - return cx.which.press(key); +impl<'a> Executor<'a> { + #[inline] + pub(super) fn new(cx: &'a mut Ctx) -> Self { Self { cx } } + + pub(super) fn handle(&mut self, key: Key) -> bool { + if self.cx.which.visible { + return self.cx.which.press(key); } - - if layer == KeymapLayer::Input && cx.input.type_(&key) { + if self.cx.input.visible && self.cx.input.type_(&key) { + return true; + } + if self.cx.help.visible && self.cx.help.type_(&key) { return true; } - if layer == KeymapLayer::Help && cx.help.type_(&key) { - return true; - } + let b = if self.cx.completion.visible { + self.matches(KeymapLayer::Completion, key).or_else(|| self.matches(KeymapLayer::Input, key)) + } else if self.cx.help.visible { + self.matches(KeymapLayer::Help, key) + } else if self.cx.input.visible { + self.matches(KeymapLayer::Input, key) + } else if self.cx.select.visible { + self.matches(KeymapLayer::Select, key) + } else if self.cx.tasks.visible { + self.matches(KeymapLayer::Tasks, key) + } else { + self.matches(KeymapLayer::Manager, key) + }; + b == Some(true) + } + #[inline] + fn matches(&mut self, layer: KeymapLayer, key: Key) -> Option { for Control { on, exec, .. } in KEYMAP.get(layer) { if on.is_empty() || on[0] != key { continue; } - return if on.len() > 1 { - cx.which.show(&key, layer) + return Some(if on.len() > 1 { + self.cx.which.show(&key, layer) } else { - Self::dispatch(cx, exec, layer) - }; + self.dispatch(exec, layer) + }); } - false + None } #[inline] - pub(super) fn dispatch(cx: &mut Ctx, exec: &[Exec], layer: KeymapLayer) -> bool { + pub(super) fn dispatch(&mut self, exec: &[Exec], layer: KeymapLayer) -> bool { let mut render = false; for e in exec { render |= match layer { - KeymapLayer::Manager => Self::manager(cx, e), - KeymapLayer::Tasks => Self::tasks(cx, e), - KeymapLayer::Select => Self::select(cx, e), - KeymapLayer::Input => Self::input(cx, e), - KeymapLayer::Help => Self::help(cx, e), - KeymapLayer::Completion => Self::completion(cx, e), + KeymapLayer::Manager => self.manager(e), + KeymapLayer::Tasks => self.tasks(e), + KeymapLayer::Select => self.select(e), + KeymapLayer::Input => self.input(e), + KeymapLayer::Help => self.help(e), + KeymapLayer::Completion => self.completion(e), KeymapLayer::Which => unreachable!(), }; } render } - fn manager(cx: &mut Ctx, exec: &Exec) -> bool { + fn manager(&mut self, exec: &Exec) -> bool { match exec.cmd.as_str() { - "escape" => cx.manager.active_mut().escape(exec), - "quit" => cx.manager.quit(&cx.tasks, exec.named.contains_key("no-cwd-file")), - "close" => cx.manager.close(&cx.tasks), - "suspend" => cx.manager.suspend(), + "escape" => self.cx.manager.active_mut().escape(exec), + "quit" => self.cx.manager.quit(&self.cx.tasks, exec.named.contains_key("no-cwd-file")), + "close" => self.cx.manager.close(&self.cx.tasks), + "suspend" => self.cx.manager.suspend(), // Navigation "arrow" => { - let step = exec.args.get(0).and_then(|s| s.parse().ok()).unwrap_or_default(); - cx.manager.active_mut().arrow(step) + let step = exec.args.first().and_then(|s| s.parse().ok()).unwrap_or_default(); + self.cx.manager.active_mut().arrow(step) } "peek" => { - let step = exec.args.get(0).and_then(|s| s.parse().ok()).unwrap_or(0); - cx.manager.active_mut().preview.arrow(step); - cx.manager.peek(true, cx.image_layer()) + let step = exec.args.first().and_then(|s| s.parse().ok()).unwrap_or(0); + self.cx.manager.active_mut().preview.arrow(step); + self.cx.manager.peek(true, self.cx.image_layer()) } - "leave" => cx.manager.active_mut().leave(), - "enter" => cx.manager.active_mut().enter(), - "back" => cx.manager.active_mut().back(), - "forward" => cx.manager.active_mut().forward(), + "leave" => self.cx.manager.active_mut().leave(), + "enter" => self.cx.manager.active_mut().enter(), + "back" => self.cx.manager.active_mut().back(), + "forward" => self.cx.manager.active_mut().forward(), "cd" => { - let url = exec.args.get(0).map(Url::from).unwrap_or_default(); + let url = exec.args.first().map(Url::from).unwrap_or_default(); if exec.named.contains_key("interactive") { - cx.manager.active_mut().cd_interactive(url) + self.cx.manager.active_mut().cd_interactive(url) } else { emit!(Cd(url)); false @@ -84,64 +104,68 @@ impl Executor { // Selection "select" => { let state = exec.named.get("state").cloned().unwrap_or("none".to_string()); - cx.manager.active_mut().select(optional_bool(&state)) + self.cx.manager.active_mut().select(optional_bool(&state)) } "select_all" => { let state = exec.named.get("state").cloned().unwrap_or("none".to_string()); - cx.manager.active_mut().select_all(optional_bool(&state)) + self.cx.manager.active_mut().select_all(optional_bool(&state)) } - "visual_mode" => cx.manager.active_mut().visual_mode(exec.named.contains_key("unset")), + "visual_mode" => self.cx.manager.active_mut().visual_mode(exec.named.contains_key("unset")), // Operation - "open" => cx.manager.open(exec.named.contains_key("interactive")), - "yank" => cx.manager.yank(exec.named.contains_key("cut")), + "open" => self.cx.manager.open(exec.named.contains_key("interactive")), + "yank" => self.cx.manager.yank(exec.named.contains_key("cut")), "paste" => { - let dest = cx.manager.cwd(); - let (cut, ref src) = cx.manager.yanked; + let dest = self.cx.manager.cwd(); + let (cut, ref src) = self.cx.manager.yanked; let force = exec.named.contains_key("force"); - if cut { cx.tasks.file_cut(src, dest, force) } else { cx.tasks.file_copy(src, dest, force) } + if cut { + self.cx.tasks.file_cut(src, dest, force) + } else { + self.cx.tasks.file_copy(src, dest, force) + } } "link" => { - let (cut, ref src) = cx.manager.yanked; + let (cut, ref src) = self.cx.manager.yanked; !cut - && cx.tasks.file_link( + && self.cx.tasks.file_link( src, - cx.manager.cwd(), + self.cx.manager.cwd(), exec.named.contains_key("relative"), exec.named.contains_key("force"), ) } "remove" => { - let targets = cx.manager.selected().into_iter().map(|f| f.url()).collect(); + let targets = self.cx.manager.selected().into_iter().map(|f| f.url()).collect(); let force = exec.named.contains_key("force"); let permanently = exec.named.contains_key("permanently"); - cx.tasks.file_remove(targets, force, permanently) + self.cx.tasks.file_remove(targets, force, permanently) } - "create" => cx.manager.create(exec.named.contains_key("force")), - "rename" => cx.manager.rename(exec.named.contains_key("force")), - "copy" => cx.manager.active().copy(exec.args.get(0).map(|s| s.as_str()).unwrap_or("")), - "shell" => cx.manager.active().shell( - exec.args.get(0).map(|e| e.as_str()).unwrap_or(""), + "create" => self.cx.manager.create(exec.named.contains_key("force")), + "rename" => self.cx.manager.rename(exec.named.contains_key("force")), + "copy" => self.cx.manager.active().copy(exec.args.first().map(|s| s.as_str()).unwrap_or("")), + "shell" => self.cx.manager.active().shell( + exec.args.first().map(|e| e.as_str()).unwrap_or(""), exec.named.contains_key("block"), exec.named.contains_key("confirm"), ), - "hidden" => cx.manager.active_mut().hidden(exec), - "linemode" => cx.manager.active_mut().linemode(exec), - "search" => match exec.args.get(0).map(|s| s.as_str()).unwrap_or("") { - "rg" => cx.manager.active_mut().search(true), - "fd" => cx.manager.active_mut().search(false), - _ => cx.manager.active_mut().search_stop(), + "hidden" => self.cx.manager.active_mut().hidden(exec), + "linemode" => self.cx.manager.active_mut().linemode(exec), + "search" => match exec.args.first().map(|s| s.as_str()).unwrap_or("") { + "rg" => self.cx.manager.active_mut().search(true), + "fd" => self.cx.manager.active_mut().search(false), + _ => self.cx.manager.active_mut().search_stop(), }, - "jump" => match exec.args.get(0).map(|s| s.as_str()).unwrap_or("") { - "fzf" => cx.manager.active_mut().jump(true), - "zoxide" => cx.manager.active_mut().jump(false), + "jump" => match exec.args.first().map(|s| s.as_str()).unwrap_or("") { + "fzf" => self.cx.manager.active_mut().jump(true), + "zoxide" => self.cx.manager.active_mut().jump(false), _ => false, }, // Find "find" => { - let query = exec.args.get(0).map(|s| s.as_str()); + let query = exec.args.first().map(|s| s.as_str()); let prev = exec.named.contains_key("previous"); let case = match (exec.named.contains_key("smart"), exec.named.contains_key("insensitive")) { @@ -149,152 +173,160 @@ impl Executor { (_, false) => FinderCase::Sensitive, (_, true) => FinderCase::Insensitive, }; - cx.manager.active_mut().find(query, prev, case) + self.cx.manager.active_mut().find(query, prev, case) } - "find_arrow" => cx.manager.active_mut().find_arrow(exec.named.contains_key("previous")), + "find_arrow" => self.cx.manager.active_mut().find_arrow(exec.named.contains_key("previous")), // Sorting "sort" => { - let b = cx.manager.active_mut().sort(exec); - cx.tasks.precache_size(&cx.manager.current().files); + let b = self.cx.manager.active_mut().sort(exec); + self.cx.tasks.precache_size(&self.cx.manager.current().files); b } // Tabs "tab_create" => { let path = if exec.named.contains_key("current") { - cx.manager.cwd().to_owned() + self.cx.manager.cwd().to_owned() } else { - exec.args.get(0).map(Url::from).unwrap_or_else(|| Url::from("/")) + exec.args.first().map(Url::from).unwrap_or_else(|| Url::from("/")) }; - cx.manager.tabs.create(&path) + self.cx.manager.tabs.create(&path) } "tab_close" => { - let idx = exec.args.get(0).and_then(|i| i.parse().ok()).unwrap_or(0); - cx.manager.tabs.close(idx) + let idx = exec.args.first().and_then(|i| i.parse().ok()).unwrap_or(0); + self.cx.manager.tabs.close(idx) } "tab_switch" => { - let step = exec.args.get(0).and_then(|s| s.parse().ok()).unwrap_or(0); + let step = exec.args.first().and_then(|s| s.parse().ok()).unwrap_or(0); let rel = exec.named.contains_key("relative"); - cx.manager.tabs.switch(step, rel) + self.cx.manager.tabs.switch(step, rel) } "tab_swap" => { - let step = exec.args.get(0).and_then(|s| s.parse().ok()).unwrap_or(0); - cx.manager.tabs.swap(step) + let step = exec.args.first().and_then(|s| s.parse().ok()).unwrap_or(0); + self.cx.manager.tabs.swap(step) } // Tasks - "tasks_show" => cx.tasks.toggle(), + "tasks_show" => self.cx.tasks.toggle(), // Help - "help" => cx.help.toggle(cx.layer()), + "help" => self.cx.help.toggle(KeymapLayer::Manager), _ => false, } } - fn tasks(cx: &mut Ctx, exec: &Exec) -> bool { + fn tasks(&mut self, exec: &Exec) -> bool { match exec.cmd.as_str() { - "close" => cx.tasks.toggle(), + "close" => self.cx.tasks.toggle(), "arrow" => { - let step = exec.args.get(0).and_then(|s| s.parse().ok()).unwrap_or(0); - if step > 0 { cx.tasks.next() } else { cx.tasks.prev() } + let step = exec.args.first().and_then(|s| s.parse().ok()).unwrap_or(0); + if step > 0 { self.cx.tasks.next() } else { self.cx.tasks.prev() } } - "inspect" => cx.tasks.inspect(), - "cancel" => cx.tasks.cancel(), + "inspect" => self.cx.tasks.inspect(), + "cancel" => self.cx.tasks.cancel(), - "help" => cx.help.toggle(cx.layer()), + "help" => self.cx.help.toggle(KeymapLayer::Tasks), _ => false, } } - fn select(cx: &mut Ctx, exec: &Exec) -> bool { + fn select(&mut self, exec: &Exec) -> bool { match exec.cmd.as_str() { - "close" => cx.select.close(exec.named.contains_key("submit")), + "close" => self.cx.select.close(exec.named.contains_key("submit")), "arrow" => { - let step: isize = exec.args.get(0).and_then(|s| s.parse().ok()).unwrap_or(0); - if step > 0 { cx.select.next(step as usize) } else { cx.select.prev(step.unsigned_abs()) } + let step: isize = exec.args.first().and_then(|s| s.parse().ok()).unwrap_or(0); + if step > 0 { + self.cx.select.next(step as usize) + } else { + self.cx.select.prev(step.unsigned_abs()) + } } - "help" => cx.help.toggle(cx.layer()), + "help" => self.cx.help.toggle(KeymapLayer::Select), _ => false, } } - fn input(cx: &mut Ctx, exec: &Exec) -> bool { + fn input(&mut self, exec: &Exec) -> bool { match exec.cmd.as_str() { - "close" => return cx.input.close(exec.named.contains_key("submit")), - "escape" => return cx.input.escape(), + "close" => return self.cx.input.close(exec.named.contains_key("submit")), + "escape" => return self.cx.input.escape(), "move" => { - let step = exec.args.get(0).and_then(|s| s.parse().ok()).unwrap_or(0); + let step = exec.args.first().and_then(|s| s.parse().ok()).unwrap_or(0); let in_operating = exec.named.contains_key("in-operating"); - return if in_operating { cx.input.move_in_operating(step) } else { cx.input.move_(step) }; + return if in_operating { + self.cx.input.move_in_operating(step) + } else { + self.cx.input.move_(step) + }; } - "complete" => return cx.completion.trigger(exec), + "complete" => return self.cx.completion.trigger(exec), _ => {} } - match cx.input.mode() { + match self.cx.input.mode() { InputMode::Normal => match exec.cmd.as_str() { - "insert" => cx.input.insert(exec.named.contains_key("append")), - "visual" => cx.input.visual(), + "insert" => self.cx.input.insert(exec.named.contains_key("append")), + "visual" => self.cx.input.visual(), - "backward" => cx.input.backward(), - "forward" => cx.input.forward(exec.named.contains_key("end-of-word")), + "backward" => self.cx.input.backward(), + "forward" => self.cx.input.forward(exec.named.contains_key("end-of-word")), "delete" => { - cx.input.delete(exec.named.contains_key("cut"), exec.named.contains_key("insert")) + self.cx.input.delete(exec.named.contains_key("cut"), exec.named.contains_key("insert")) } - "yank" => cx.input.yank(), - "paste" => cx.input.paste(exec.named.contains_key("before")), + "yank" => self.cx.input.yank(), + "paste" => self.cx.input.paste(exec.named.contains_key("before")), - "undo" => cx.input.undo(), - "redo" => cx.input.redo(), + "undo" => self.cx.input.undo(), + "redo" => self.cx.input.redo(), - "help" => cx.help.toggle(cx.layer()), + "help" => self.cx.help.toggle(KeymapLayer::Input), _ => false, }, InputMode::Insert => false, } } - fn help(cx: &mut Ctx, exec: &Exec) -> bool { + fn help(&mut self, exec: &Exec) -> bool { match exec.cmd.as_str() { - "close" => cx.help.toggle(cx.layer()), - "escape" => cx.help.escape(), + "close" => self.cx.help.toggle(KeymapLayer::Help), + "escape" => self.cx.help.escape(), "arrow" => { - let step = exec.args.get(0).and_then(|s| s.parse().ok()).unwrap_or(0); - cx.help.arrow(step) + let step = exec.args.first().and_then(|s| s.parse().ok()).unwrap_or(0); + self.cx.help.arrow(step) } - "filter" => cx.help.filter(), + "filter" => self.cx.help.filter(), _ => false, } } - fn completion(cx: &mut Ctx, exec: &Exec) -> bool { + fn completion(&mut self, exec: &Exec) -> bool { match exec.cmd.as_str() { - "trigger" => cx.completion.trigger(exec), - "show" => cx.completion.show(exec), - "close" => cx.completion.close(exec.named.contains_key("submit")), + "trigger" => self.cx.completion.trigger(exec), + "show" => self.cx.completion.show(exec), + "close" => self.cx.completion.close(exec.named.contains_key("submit")), "arrow" => { let step: isize = exec.args.first().and_then(|s| s.parse().ok()).unwrap_or(0); if step > 0 { - cx.completion.next(step as usize) + self.cx.completion.next(step as usize) } else { - cx.completion.prev(step.unsigned_abs()) + self.cx.completion.prev(step.unsigned_abs()) } } - "help" => cx.help.toggle(cx.layer()), + "help" => self.cx.help.toggle(KeymapLayer::Completion), _ => false, } }