perf: new event system (#561)

This commit is contained in:
三咲雅 · Misaki Masa 2024-01-22 18:43:50 +08:00 committed by GitHub
parent acb8b47eee
commit 56ede51c53
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
93 changed files with 353 additions and 328 deletions

View File

@ -1,4 +1,4 @@
use std::borrow::Cow;
use std::{borrow::Cow, collections::VecDeque};
use serde::Deserialize;
use yazi_shared::event::Exec;
@ -14,17 +14,8 @@ pub struct Control {
}
impl Control {
pub fn to_call(&self) -> Vec<Exec> {
self
.exec
.iter()
.map(|e| Exec {
cmd: e.cmd.clone(),
args: e.args.clone(),
named: e.named.clone(),
..Default::default()
})
.collect()
pub fn to_seq(&self) -> VecDeque<Exec> {
self.exec.iter().map(|e| e.clone_without_data()).collect()
}
}

View File

@ -6,9 +6,9 @@ pub struct Opt {
step: isize,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self {
Self { step: e.args.first().and_then(|s| s.parse().ok()).unwrap_or(0) }
impl From<Exec> for Opt {
fn from(mut e: Exec) -> Self {
Self { step: e.take_first().and_then(|s| s.parse().ok()).unwrap_or(0) }
}
}

View File

@ -6,20 +6,21 @@ pub struct Opt {
submit: bool,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self { Self { submit: e.named.contains_key("submit") } }
impl From<Exec> for Opt {
fn from(e: Exec) -> Self { Self { submit: e.named.contains_key("submit") } }
}
impl Completion {
#[inline]
pub fn _close() {
emit!(Call(Exec::call("close", vec![]).vec(), Layer::Completion));
emit!(Call(Exec::call("close", vec![]), Layer::Completion));
}
pub fn close(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt;
if opt.submit {
Input::_complete(self.selected(), self.ticket);
if let Some(s) = self.selected().filter(|_| opt.submit) {
Input::_complete(s, self.ticket);
}
self.caches.clear();

View File

@ -6,20 +6,20 @@ use crate::completion::Completion;
const LIMIT: usize = 30;
pub struct Opt<'a> {
cache: &'a Vec<String>,
cache_name: &'a str,
word: &'a str,
pub struct Opt {
cache: Vec<String>,
cache_name: String,
word: String,
ticket: usize,
}
impl<'a> From<&'a Exec> for Opt<'a> {
fn from(e: &'a Exec) -> Self {
impl From<Exec> for Opt {
fn from(mut e: Exec) -> Self {
Self {
cache: &e.args,
cache_name: e.named.get("cache-name").map(|n| n.as_str()).unwrap_or_default(),
word: e.named.get("word").map(|w| w.as_str()).unwrap_or_default(),
ticket: e.named.get("ticket").and_then(|v| v.parse().ok()).unwrap_or(0),
cache: mem::take(&mut e.args),
cache_name: e.take_name("cache-name").unwrap_or_default(),
word: e.take_name("word").unwrap_or_default(),
ticket: e.take_name("ticket").and_then(|v| v.parse().ok()).unwrap_or(0),
}
}
}
@ -54,7 +54,7 @@ impl Completion {
prefixed.into_iter().map(ToOwned::to_owned).collect()
}
pub fn show<'a>(&mut self, opt: impl Into<Opt<'a>>) {
pub fn show(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt;
if self.ticket != opt.ticket {
return;
@ -63,12 +63,12 @@ impl Completion {
if !opt.cache.is_empty() {
self.caches.insert(opt.cache_name.to_owned(), opt.cache.clone());
}
let Some(cache) = self.caches.get(opt.cache_name) else {
let Some(cache) = self.caches.get(&opt.cache_name) else {
return;
};
self.ticket = opt.ticket;
self.cands = Self::match_candidates(opt.word, cache);
self.cands = Self::match_candidates(&opt.word, cache);
if self.cands.is_empty() {
return render!(mem::replace(&mut self.visible, false));
}

View File

@ -5,16 +5,16 @@ use yazi_shared::{emit, event::Exec, render, Layer};
use crate::completion::Completion;
pub struct Opt<'a> {
word: &'a str,
pub struct Opt {
word: String,
ticket: usize,
}
impl<'a> From<&'a Exec> for Opt<'a> {
fn from(e: &'a Exec) -> Self {
impl From<Exec> for Opt {
fn from(mut e: Exec) -> Self {
Self {
word: e.args.first().map(|s| s.as_str()).unwrap_or_default(),
ticket: e.named.get("ticket").and_then(|s| s.parse().ok()).unwrap_or(0),
word: e.take_first().unwrap_or_default(),
ticket: e.take_name("ticket").and_then(|s| s.parse().ok()).unwrap_or(0),
}
}
}
@ -23,23 +23,23 @@ impl Completion {
#[inline]
pub fn _trigger(word: &str, ticket: usize) {
emit!(Call(
Exec::call("trigger", vec![word.to_owned()]).with("ticket", ticket).vec(),
Exec::call("trigger", vec![word.to_owned()]).with("ticket", ticket),
Layer::Completion
));
}
pub fn trigger<'a>(&mut self, opt: impl Into<Opt<'a>>) {
pub fn trigger(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt;
if opt.ticket < self.ticket {
return;
}
self.ticket = opt.ticket;
let (parent, child) = Self::split_path(opt.word);
let (parent, child) = Self::split_path(&opt.word);
if self.caches.contains_key(&parent) {
return self.show(
&Exec::call("show", vec![])
Exec::call("show", vec![])
.with("cache-name", parent)
.with("word", child)
.with("ticket", opt.ticket),
@ -67,8 +67,7 @@ impl Completion {
Exec::call("show", cache)
.with("cache-name", parent)
.with("word", child)
.with("ticket", ticket)
.vec(),
.with("ticket", ticket),
Layer::Completion
));
}

View File

@ -23,7 +23,7 @@ impl Completion {
pub fn limit(&self) -> usize { self.cands.len().min(10) }
#[inline]
pub fn selected(&self) -> &String { &self.cands[self.cursor] }
pub fn selected(&self) -> Option<&String> { self.cands.get(self.cursor) }
// --- Cursor
#[inline]

View File

@ -6,9 +6,9 @@ pub struct Opt {
step: isize,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self {
Self { step: e.args.first().and_then(|s| s.parse().ok()).unwrap_or(0) }
impl From<Exec> for Opt {
fn from(mut e: Exec) -> Self {
Self { step: e.take_first().and_then(|s| s.parse().ok()).unwrap_or(0) }
}
}
impl From<isize> for Opt {

View File

@ -3,7 +3,7 @@ use yazi_shared::{event::Exec, render};
use crate::help::Help;
impl Help {
pub fn escape(&mut self, _: &Exec) {
pub fn escape(&mut self, _: Exec) {
if self.in_filter.is_none() {
return self.toggle(self.layer);
}

View File

@ -4,7 +4,7 @@ use yazi_shared::{event::Exec, render};
use crate::{help::Help, input::Input};
impl Help {
pub fn filter(&mut self, _: &Exec) {
pub fn filter(&mut self, _: Exec) {
let mut input = Input::default();
input.position = Position::new(Origin::BottomLeft, Offset::line());

View File

@ -6,8 +6,8 @@ pub struct Opt {
under: bool,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self { Self { under: e.named.contains_key("under") } }
impl From<Exec> for Opt {
fn from(e: Exec) -> Self { Self { under: e.named.contains_key("under") } }
}
impl From<bool> for Opt {
fn from(under: bool) -> Self { Self { under } }

View File

@ -3,7 +3,7 @@ use yazi_shared::{event::Exec, CharKind};
use crate::input::Input;
impl Input {
pub fn backward(&mut self, _: &Exec) {
pub fn backward(&mut self, _: Exec) {
let snap = self.snap();
if snap.cursor == 0 {
return self.move_(0);

View File

@ -6,8 +6,8 @@ pub struct Opt {
submit: bool,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self { Self { submit: e.named.contains_key("submit") } }
impl From<Exec> for Opt {
fn from(e: Exec) -> Self { Self { submit: e.named.contains_key("submit") } }
}
impl From<bool> for Opt {
fn from(submit: bool) -> Self { Self { submit } }

View File

@ -4,16 +4,16 @@ use yazi_shared::{emit, event::Exec, render, Layer};
use crate::input::Input;
pub struct Opt<'a> {
word: &'a str,
pub struct Opt {
word: String,
ticket: usize,
}
impl<'a> From<&'a Exec> for Opt<'a> {
fn from(e: &'a Exec) -> Self {
impl From<Exec> for Opt {
fn from(mut e: Exec) -> Self {
Self {
word: e.args.first().map(|w| w.as_str()).unwrap_or_default(),
ticket: e.named.get("ticket").and_then(|s| s.parse().ok()).unwrap_or(0),
word: e.take_first().unwrap_or_default(),
ticket: e.take_name("ticket").and_then(|s| s.parse().ok()).unwrap_or(0),
}
}
}
@ -21,13 +21,10 @@ impl<'a> From<&'a Exec> for Opt<'a> {
impl Input {
#[inline]
pub fn _complete(word: &str, ticket: usize) {
emit!(Call(
Exec::call("complete", vec![word.to_owned()]).with("ticket", ticket).vec(),
Layer::Input
));
emit!(Call(Exec::call("complete", vec![word.to_owned()]).with("ticket", ticket), Layer::Input));
}
pub fn complete<'a>(&mut self, opt: impl Into<Opt<'a>>) {
pub fn complete(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt;
if self.ticket != opt.ticket {
return;

View File

@ -7,8 +7,8 @@ pub struct Opt {
insert: bool,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self {
impl From<Exec> for Opt {
fn from(e: Exec) -> Self {
Self { cut: e.named.contains_key("cut"), insert: e.named.contains_key("insert") }
}
}

View File

@ -4,8 +4,8 @@ use crate::{completion::Completion, input::{op::InputOp, Input, InputMode}};
pub struct Opt;
impl From<&Exec> for Opt {
fn from(_: &Exec) -> Self { Self }
impl From<Exec> for Opt {
fn from(_: Exec) -> Self { Self }
}
impl From<()> for Opt {
fn from(_: ()) -> Self { Self }

View File

@ -6,8 +6,8 @@ pub struct Opt {
end_of_word: bool,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self { Self { end_of_word: e.named.contains_key("end-of-word") } }
impl From<Exec> for Opt {
fn from(e: Exec) -> Self { Self { end_of_word: e.named.contains_key("end-of-word") } }
}
impl Input {

View File

@ -6,8 +6,8 @@ pub struct Opt {
append: bool,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self { Self { append: e.named.contains_key("append") } }
impl From<Exec> for Opt {
fn from(e: Exec) -> Self { Self { append: e.named.contains_key("append") } }
}
impl From<bool> for Opt {
fn from(append: bool) -> Self { Self { append } }

View File

@ -4,14 +4,12 @@ use yazi_shared::{event::Exec, render, CharKind};
use crate::input::Input;
pub struct Opt<'a> {
kind: &'a str,
pub struct Opt {
kind: String,
}
impl<'a> From<&'a Exec> for Opt<'a> {
fn from(e: &'a Exec) -> Self {
Self { kind: e.args.first().map(|s| s.as_str()).unwrap_or_default() }
}
impl From<Exec> for Opt {
fn from(mut e: Exec) -> Self { Self { kind: e.take_first().unwrap_or_default() } }
}
impl Input {
@ -67,7 +65,7 @@ impl Input {
input.take(n).fold(0, |acc, c| acc + c.len_utf8())
}
pub fn kill<'a>(&mut self, opt: impl Into<Opt<'a>>) {
pub fn kill(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt;
let snap = self.snap_mut();

View File

@ -8,10 +8,10 @@ pub struct Opt {
in_operating: bool,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self {
impl From<Exec> for Opt {
fn from(mut e: Exec) -> Self {
Self {
step: e.args.first().and_then(|s| s.parse().ok()).unwrap_or(0),
step: e.take_first().and_then(|s| s.parse().ok()).unwrap_or(0),
in_operating: e.named.contains_key("in-operating"),
}
}

View File

@ -6,8 +6,8 @@ pub struct Opt {
before: bool,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self { Self { before: e.named.contains_key("before") } }
impl From<Exec> for Opt {
fn from(e: Exec) -> Self { Self { before: e.named.contains_key("before") } }
}
impl Input {

View File

@ -3,7 +3,7 @@ use yazi_shared::{event::Exec, render};
use crate::input::Input;
impl Input {
pub fn redo(&mut self, _: &Exec) {
pub fn redo(&mut self, _: Exec) {
render!(self.snaps.redo());
}
}

View File

@ -9,16 +9,16 @@ pub struct Opt {
tx: mpsc::UnboundedSender<Result<String, InputError>>,
}
impl TryFrom<&Exec> for Opt {
impl TryFrom<Exec> for Opt {
type Error = ();
fn try_from(e: &Exec) -> Result<Self, Self::Error> { e.take_data().ok_or(()) }
fn try_from(mut e: Exec) -> Result<Self, Self::Error> { e.take_data().ok_or(()) }
}
impl Input {
pub fn _show(cfg: InputCfg) -> mpsc::UnboundedReceiver<Result<String, InputError>> {
let (tx, rx) = mpsc::unbounded_channel();
emit!(Call(Exec::call("show", vec![]).with_data(Opt { cfg, tx }).vec(), Layer::Input));
emit!(Call(Exec::call("show", vec![]).with_data(Opt { cfg, tx }), Layer::Input));
rx
}

View File

@ -5,8 +5,8 @@ use crate::input::{Input, InputMode};
pub struct Opt;
impl From<&Exec> for Opt {
fn from(_: &Exec) -> Self { Self }
impl From<Exec> for Opt {
fn from(_: Exec) -> Self { Self }
}
impl Input {

View File

@ -3,7 +3,7 @@ use yazi_shared::{event::Exec, render};
use crate::input::{Input, InputMode};
impl Input {
pub fn undo(&mut self, _: &Exec) {
pub fn undo(&mut self, _: Exec) {
if !self.snaps.undo() {
return;
}

View File

@ -4,7 +4,7 @@ use crate::input::{op::InputOp, Input, InputMode};
impl Input {
#[inline]
pub fn visual(&mut self, _: &Exec) {
pub fn visual(&mut self, _: Exec) {
let snap = self.snap_mut();
if snap.mode != InputMode::Normal {
return;

View File

@ -3,7 +3,7 @@ use yazi_shared::{event::Exec, render};
use crate::input::{op::InputOp, Input};
impl Input {
pub fn yank(&mut self, _: &Exec) {
pub fn yank(&mut self, _: Exec) {
match self.snap().op {
InputOp::None => {
self.snap_mut().op = InputOp::Yank(self.snap().cursor);

View File

@ -3,7 +3,7 @@ use yazi_shared::event::Exec;
use crate::{manager::Manager, tasks::Tasks};
impl Manager {
pub fn close(&mut self, _: &Exec, tasks: &Tasks) {
pub fn close(&mut self, _: Exec, tasks: &Tasks) {
if self.tabs.len() > 1 {
return self.tabs.close(self.tabs.idx);
}

View File

@ -10,8 +10,8 @@ pub struct Opt {
force: bool,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self { Self { force: e.named.contains_key("force") } }
impl From<Exec> for Opt {
fn from(e: Exec) -> Self { Self { force: e.named.contains_key("force") } }
}
impl Manager {

View File

@ -8,8 +8,8 @@ pub struct Opt {
url: Option<Url>,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self { Self { url: e.args.first().map(Url::from) } }
impl From<Exec> for Opt {
fn from(mut e: Exec) -> Self { Self { url: e.take_first().map(Url::from) } }
}
impl From<Option<Url>> for Opt {
fn from(url: Option<Url>) -> Self { Self { url } }
@ -19,7 +19,7 @@ impl Manager {
#[inline]
pub fn _hover(url: Option<Url>) {
emit!(Call(
Exec::call("hover", url.map_or_else(Vec::new, |u| vec![u.to_string()])).vec(),
Exec::call("hover", url.map_or_else(Vec::new, |u| vec![u.to_string()])),
Layer::Manager
));
}

View File

@ -7,8 +7,8 @@ pub struct Opt {
force: bool,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self {
impl From<Exec> for Opt {
fn from(e: Exec) -> Self {
Self { relative: e.named.contains_key("relative"), force: e.named.contains_key("force") }
}
}

View File

@ -12,8 +12,8 @@ pub struct Opt {
interactive: bool,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self {
impl From<Exec> for Opt {
fn from(mut e: Exec) -> Self {
Self { targets: e.take_data(), interactive: e.named.contains_key("interactive") }
}
}
@ -57,7 +57,7 @@ impl Manager {
#[inline]
pub fn _open_do(interactive: bool, targets: Vec<(Url, Option<String>)>) {
emit!(Call(
Exec::call("open_do", vec![]).with_bool("interactive", interactive).with_data(targets).vec(),
Exec::call("open_do", vec![]).with_bool("interactive", interactive).with_data(targets),
Layer::Manager
));
}

View File

@ -7,8 +7,8 @@ pub struct Opt {
follow: bool,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self {
impl From<Exec> for Opt {
fn from(e: Exec) -> Self {
Self { force: e.named.contains_key("force"), follow: e.named.contains_key("follow") }
}
}

View File

@ -10,12 +10,12 @@ pub struct Opt {
upper_bound: bool,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self {
impl From<Exec> for Opt {
fn from(mut e: Exec) -> Self {
Self {
skip: e.args.first().and_then(|s| s.parse().ok()),
skip: e.take_first().and_then(|s| s.parse().ok()),
force: e.named.contains_key("force"),
only_if: e.named.get("only-if").map(Url::from),
only_if: e.take_name("only-if").map(Url::from),
upper_bound: e.named.contains_key("upper-bound"),
}
}
@ -27,7 +27,7 @@ impl From<bool> for Opt {
impl Manager {
#[inline]
pub fn _peek(force: bool) {
emit!(Call(Exec::call("peek", vec![]).with_bool("force", force).vec(), Layer::Manager));
emit!(Call(Exec::call("peek", vec![]).with_bool("force", force), Layer::Manager));
}
pub fn peek(&mut self, opt: impl Into<Opt>) {

View File

@ -10,8 +10,8 @@ pub struct Opt {
impl From<()> for Opt {
fn from(_: ()) -> Self { Self::default() }
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self { Self { no_cwd_file: e.named.contains_key("no-cwd-file") } }
impl From<Exec> for Opt {
fn from(e: Exec) -> Self { Self { no_cwd_file: e.named.contains_key("no-cwd-file") } }
}
impl Manager {

View File

@ -7,10 +7,10 @@ use crate::{manager::Manager, tasks::Tasks};
impl Manager {
#[inline]
pub fn _refresh() {
emit!(Call(Exec::call("refresh", vec![]).vec(), Layer::Manager));
emit!(Call(Exec::call("refresh", vec![]), Layer::Manager));
}
pub fn refresh(&mut self, _: &Exec, tasks: &Tasks) {
pub fn refresh(&mut self, _: Exec, tasks: &Tasks) {
env::set_current_dir(self.cwd()).ok();
env::set_var("PWD", self.cwd());

View File

@ -7,8 +7,8 @@ pub struct Opt {
permanently: bool,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self {
impl From<Exec> for Opt {
fn from(e: Exec) -> Self {
Self {
force: e.named.contains_key("force"),
permanently: e.named.contains_key("permanently"),

View File

@ -9,18 +9,18 @@ use yazi_shared::{event::Exec, fs::{max_common_root, File, FilesOp, Url}, term::
use crate::{input::Input, manager::Manager};
pub struct Opt<'a> {
pub struct Opt {
force: bool,
empty: &'a str,
cursor: &'a str,
empty: String,
cursor: String,
}
impl<'a> From<&'a Exec> for Opt<'a> {
fn from(e: &'a Exec) -> Self {
impl From<Exec> for Opt {
fn from(mut e: 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(),
empty: e.take_name("empty").unwrap_or_default(),
cursor: e.take_name("cursor").unwrap_or_default(),
}
}
}
@ -51,7 +51,7 @@ impl Manager {
Ok(Self::_hover(Some(new)))
}
pub fn rename<'a>(&self, opt: impl Into<Opt<'a>>) {
pub fn rename(&self, opt: impl Into<Opt>) {
if self.active().in_selecting() {
return self.bulk_rename();
}
@ -61,8 +61,8 @@ impl Manager {
};
let opt = opt.into() as Opt;
let name = Self::empty_url_part(&hovered, opt.empty);
let cursor = match opt.cursor {
let name = Self::empty_url_part(&hovered, &opt.empty);
let cursor = match opt.cursor.as_str() {
"start" => Some(0),
"before_ext" => name
.chars()

View File

@ -9,9 +9,9 @@ pub struct Opt {
units: i16,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self {
Self { units: e.args.first().and_then(|s| s.parse().ok()).unwrap_or(0) }
impl From<Exec> for Opt {
fn from(mut e: Exec) -> Self {
Self { units: e.take_first().and_then(|s| s.parse().ok()).unwrap_or(0) }
}
}

View File

@ -4,7 +4,7 @@ use yazi_shared::event::Exec;
use crate::manager::Manager;
impl Manager {
pub fn suspend(&mut self, _: &Exec) {
pub fn suspend(&mut self, _: Exec) {
#[cfg(unix)]
tokio::spawn(async move {
Scheduler::app_stop().await;

View File

@ -6,9 +6,9 @@ pub struct Opt {
idx: usize,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self {
Self { idx: e.args.first().and_then(|i| i.parse().ok()).unwrap_or(0) }
impl From<Exec> for Opt {
fn from(mut e: Exec) -> Self {
Self { idx: e.take_first().and_then(|i| i.parse().ok()).unwrap_or(0) }
}
}

View File

@ -9,12 +9,12 @@ pub struct Opt {
current: bool,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self {
impl From<Exec> for Opt {
fn from(mut e: Exec) -> Self {
let mut opt = Self { url: None, current: e.named.contains_key("current") };
if !opt.current {
opt.url = Some(e.args.first().map_or_else(|| Url::from("."), Url::from));
opt.url = Some(e.take_first().map_or_else(|| Url::from("."), Url::from));
}
opt
}

View File

@ -6,9 +6,9 @@ pub struct Opt {
step: isize,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self {
Self { step: e.args.first().and_then(|s| s.parse().ok()).unwrap_or(0) }
impl From<Exec> for Opt {
fn from(mut e: Exec) -> Self {
Self { step: e.take_first().and_then(|s| s.parse().ok()).unwrap_or(0) }
}
}

View File

@ -7,10 +7,10 @@ pub struct Opt {
relative: bool,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self {
impl From<Exec> for Opt {
fn from(mut e: Exec) -> Self {
Self {
step: e.args.first().and_then(|s| s.parse().ok()).unwrap_or(0),
step: e.take_first().and_then(|s| s.parse().ok()).unwrap_or(0),
relative: e.named.contains_key("relative"),
}
}

View File

@ -8,10 +8,12 @@ pub struct Opt {
op: FilesOp,
}
impl TryFrom<&Exec> for Opt {
impl TryFrom<Exec> for Opt {
type Error = ();
fn try_from(e: &Exec) -> Result<Self, Self::Error> { Ok(Self { op: e.take_data().ok_or(())? }) }
fn try_from(mut e: Exec) -> Result<Self, Self::Error> {
Ok(Self { op: e.take_data().ok_or(())? })
}
}
impl Manager {

View File

@ -9,10 +9,12 @@ pub struct Opt {
data: ValueSendable,
}
impl TryFrom<&Exec> for Opt {
impl TryFrom<Exec> for Opt {
type Error = ();
fn try_from(e: &Exec) -> Result<Self, Self::Error> { Ok(Self { data: e.take_data().ok_or(())? }) }
fn try_from(mut e: Exec) -> Result<Self, Self::Error> {
Ok(Self { data: e.take_data().ok_or(())? })
}
}
impl Manager {

View File

@ -8,11 +8,11 @@ pub struct Opt {
only_if: Option<Url>,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self {
impl From<Exec> for Opt {
fn from(mut e: Exec) -> Self {
Self {
page: e.args.first().and_then(|s| s.parse().ok()),
only_if: e.named.get("only-if").map(Url::from),
page: e.take_first().and_then(|s| s.parse().ok()),
only_if: e.take_name("only-if").map(Url::from),
}
}
}
@ -24,13 +24,13 @@ impl From<()> for Opt {
impl Manager {
#[inline]
pub fn _update_paged() {
emit!(Call(Exec::call("update_paged", vec![]).vec(), Layer::Manager));
emit!(Call(Exec::call("update_paged", vec![]), Layer::Manager));
}
#[inline]
pub fn _update_paged_by(page: usize, only_if: &Url) {
emit!(Call(
Exec::call("update_paged", vec![page.to_string()]).with("only-if", only_if.to_string()).vec(),
Exec::call("update_paged", vec![page.to_string()]).with("only-if", only_if.to_string()),
Layer::Manager
));
}

View File

@ -6,8 +6,8 @@ pub struct Opt {
cut: bool,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self { Self { cut: e.named.contains_key("cut") } }
impl From<Exec> for Opt {
fn from(e: Exec) -> Self { Self { cut: e.named.contains_key("cut") } }
}
impl Manager {

View File

@ -6,9 +6,9 @@ pub struct Opt {
step: isize,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self {
Self { step: e.args.first().and_then(|s| s.parse().ok()).unwrap_or(0) }
impl From<Exec> for Opt {
fn from(mut e: Exec) -> Self {
Self { step: e.take_first().and_then(|s| s.parse().ok()).unwrap_or(0) }
}
}

View File

@ -7,8 +7,8 @@ pub struct Opt {
submit: bool,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self { Self { submit: e.named.contains_key("submit") } }
impl From<Exec> for Opt {
fn from(e: Exec) -> Self { Self { submit: e.named.contains_key("submit") } }
}
impl From<bool> for Opt {
fn from(submit: bool) -> Self { Self { submit } }

View File

@ -10,16 +10,16 @@ pub struct Opt {
tx: oneshot::Sender<Result<usize>>,
}
impl TryFrom<&Exec> for Opt {
impl TryFrom<Exec> for Opt {
type Error = ();
fn try_from(e: &Exec) -> Result<Self, Self::Error> { e.take_data().ok_or(()) }
fn try_from(mut e: Exec) -> Result<Self, Self::Error> { e.take_data().ok_or(()) }
}
impl Select {
pub async fn _show(cfg: SelectCfg) -> Result<usize> {
let (tx, rx) = oneshot::channel();
emit!(Call(Exec::call("show", vec![]).with_data(Opt { cfg, tx }).vec(), Layer::Select));
emit!(Call(Exec::call("show", vec![]).with_data(Opt { cfg, tx }), Layer::Select));
rx.await.unwrap_or_else(|_| Term::goodbye(|| false))
}

View File

@ -6,9 +6,9 @@ pub struct Opt {
step: Step,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self {
Self { step: e.args.first().and_then(|s| s.parse().ok()).unwrap_or_default() }
impl From<Exec> for Opt {
fn from(mut e: Exec) -> Self {
Self { step: e.take_first().and_then(|s| s.parse().ok()).unwrap_or_default() }
}
}

View File

@ -6,8 +6,8 @@ pub struct Opt;
impl From<()> for Opt {
fn from(_: ()) -> Self { Self }
}
impl From<&Exec> for Opt {
fn from(_: &Exec) -> Self { Self }
impl From<Exec> for Opt {
fn from(_: Exec) -> Self { Self }
}
impl Tab {

View File

@ -12,9 +12,9 @@ pub struct Opt {
interactive: bool,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self {
let mut target = Url::from(e.args.first().map(|s| s.as_str()).unwrap_or(""));
impl From<Exec> for Opt {
fn from(mut e: Exec) -> Self {
let mut target = Url::from(e.take_first().unwrap_or_default());
if target.is_regular() {
target.set_path(expand_path(&target))
}
@ -29,7 +29,7 @@ impl From<Url> for Opt {
impl Tab {
#[inline]
pub fn _cd(target: &Url) {
emit!(Call(Exec::call("cd", vec![target.to_string()]).vec(), Layer::Manager));
emit!(Call(Exec::call("cd", vec![target.to_string()]), Layer::Manager));
}
pub fn cd(&mut self, opt: impl Into<Opt>) {

View File

@ -4,22 +4,22 @@ use yazi_shared::event::Exec;
use crate::{tab::Tab, CLIPBOARD};
pub struct Opt<'a> {
type_: &'a str,
pub struct Opt {
type_: String,
}
impl<'a> From<&'a Exec> for Opt<'a> {
fn from(e: &'a Exec) -> Self { Self { type_: e.args.first().map(|s| s.as_str()).unwrap_or("") } }
impl From<Exec> for Opt {
fn from(mut e: Exec) -> Self { Self { type_: e.take_first().unwrap_or_default() } }
}
impl Tab {
pub fn copy<'a>(&self, opt: impl Into<Opt<'a>>) {
pub fn copy(&self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt;
let mut s = OsString::new();
let mut it = self.selected().into_iter().peekable();
while let Some(f) = it.next() {
s.push(match opt.type_ {
s.push(match opt.type_.as_str() {
"path" => f.url.as_os_str(),
"dirname" => f.url.parent().map_or(OsStr::new(""), |p| p.as_os_str()),
"filename" => f.name().unwrap_or(OsStr::new("")),

View File

@ -8,8 +8,8 @@ pub struct Opt;
impl From<()> for Opt {
fn from(_: ()) -> Self { Self }
}
impl From<&Exec> for Opt {
fn from(_: &Exec) -> Self { Self }
impl From<Exec> for Opt {
fn from(_: Exec) -> Self { Self }
}
impl Tab {

View File

@ -13,15 +13,15 @@ bitflags! {
}
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self {
e.named.iter().fold(Opt::empty(), |acc, (k, _)| match k.as_bytes() {
b"all" => Self::all(),
b"find" => acc | Self::FIND,
b"visual" => acc | Self::VISUAL,
b"select" => acc | Self::SELECT,
b"filter" => acc | Self::FILTER,
b"search" => acc | Self::SEARCH,
impl From<Exec> for Opt {
fn from(e: Exec) -> Self {
e.named.iter().fold(Opt::empty(), |acc, (k, _)| match k.as_str() {
"all" => Self::all(),
"find" => acc | Self::FIND,
"visual" => acc | Self::VISUAL,
"select" => acc | Self::SELECT,
"filter" => acc | Self::FILTER,
"search" => acc | Self::SEARCH,
_ => acc,
})
}
@ -47,7 +47,7 @@ impl Tab {
#[inline]
fn escape_filter(&mut self) -> bool {
let b = self.current.files.filter().is_some();
self.filter_do(super::filter::Opt { query: "", ..Default::default() });
self.filter_do(super::filter::Opt::default());
b
}

View File

@ -8,24 +8,24 @@ use yazi_shared::{emit, event::Exec, render, Debounce, InputError, Layer};
use crate::{folder::{Filter, FilterCase}, input::Input, manager::Manager, tab::Tab};
#[derive(Default)]
pub struct Opt<'a> {
pub query: &'a str,
pub struct Opt {
pub query: String,
pub case: FilterCase,
pub done: bool,
}
impl<'a> From<&'a Exec> for Opt<'a> {
fn from(e: &'a Exec) -> Self {
impl From<Exec> for Opt {
fn from(mut e: Exec) -> Self {
Self {
query: e.args.first().map(|s| s.as_str()).unwrap_or_default(),
case: e.into(),
query: e.take_first().unwrap_or_default(),
case: FilterCase::from(&e),
done: e.named.contains_key("done"),
}
}
}
impl Tab {
pub fn filter<'a>(&mut self, opt: impl Into<Opt<'a>>) {
pub fn filter(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt;
tokio::spawn(async move {
let rx = Input::_show(InputCfg::filter());
@ -43,20 +43,19 @@ impl Tab {
Exec::call("filter_do", vec![s])
.with_bool("smart", opt.case == FilterCase::Smart)
.with_bool("insensitive", opt.case == FilterCase::Insensitive)
.with_bool("done", done)
.vec(),
.with_bool("done", done),
Layer::Manager
));
}
});
}
pub fn filter_do<'a>(&mut self, opt: impl Into<Opt<'a>>) {
pub fn filter_do(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt;
let filter = if opt.query.is_empty() {
None
} else if let Ok(f) = Filter::new(opt.query, opt.case) {
} else if let Ok(f) = Filter::new(&opt.query, opt.case) {
Some(f)
} else {
return;

View File

@ -7,18 +7,18 @@ use yazi_shared::{emit, event::Exec, render, Debounce, InputError, Layer};
use crate::{folder::FilterCase, input::Input, tab::{Finder, Tab}};
pub struct Opt<'a> {
query: Option<&'a str>,
pub struct Opt {
query: Option<String>,
prev: bool,
case: FilterCase,
}
impl<'a> From<&'a Exec> for Opt<'a> {
fn from(e: &'a Exec) -> Self {
impl From<Exec> for Opt {
fn from(mut e: Exec) -> Self {
Self {
query: e.args.first().map(|s| s.as_str()),
query: e.take_first(),
prev: e.named.contains_key("previous"),
case: e.into(),
case: FilterCase::from(&e),
}
}
}
@ -27,12 +27,12 @@ pub struct ArrowOpt {
prev: bool,
}
impl From<&Exec> for ArrowOpt {
fn from(e: &Exec) -> Self { Self { prev: e.named.contains_key("previous") } }
impl From<Exec> for ArrowOpt {
fn from(e: Exec) -> Self { Self { prev: e.named.contains_key("previous") } }
}
impl Tab {
pub fn find<'a>(&mut self, opt: impl Into<Opt<'a>>) {
pub fn find(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt;
tokio::spawn(async move {
let rx = Input::_show(InputCfg::find(opt.prev));
@ -45,15 +45,14 @@ impl Tab {
Exec::call("find_do", vec![s])
.with_bool("previous", opt.prev)
.with_bool("smart", opt.case == FilterCase::Smart)
.with_bool("insensitive", opt.case == FilterCase::Insensitive)
.vec(),
.with_bool("insensitive", opt.case == FilterCase::Insensitive),
Layer::Manager
));
}
});
}
pub fn find_do<'a>(&mut self, opt: impl Into<Opt<'a>>) {
pub fn find_do(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as Opt;
let Some(query) = opt.query else {
return;
@ -62,7 +61,7 @@ impl Tab {
return self.escape(super::escape::Opt::FIND);
}
let Ok(finder) = Finder::new(query, opt.case) else {
let Ok(finder) = Finder::new(&query, opt.case) else {
return;
};
if matches!(&self.finder, Some(f) if f.filter == finder.filter) {

View File

@ -3,10 +3,10 @@ use yazi_shared::event::Exec;
use crate::{manager::Manager, tab::Tab};
impl Tab {
pub fn hidden(&mut self, e: &Exec) {
self.conf.show_hidden = match e.args.first().map(|s| s.as_bytes()) {
Some(b"show") => true,
Some(b"hide") => false,
pub fn hidden(&mut self, e: Exec) {
self.conf.show_hidden = match e.args.first().map(|s| s.as_str()) {
Some("show") => true,
Some("hide") => false,
_ => !self.conf.show_hidden,
};

View File

@ -15,8 +15,8 @@ pub enum OptType {
Zoxide,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self {
impl From<Exec> for Opt {
fn from(e: Exec) -> Self {
Self {
type_: match e.args.first().map(|s| s.as_str()) {
Some("fzf") => OptType::Fzf,

View File

@ -8,8 +8,8 @@ pub struct Opt;
impl From<()> for Opt {
fn from(_: ()) -> Self { Self }
}
impl From<&Exec> for Opt {
fn from(_: &Exec) -> Self { Self }
impl From<Exec> for Opt {
fn from(_: Exec) -> Self { Self }
}
impl Tab {

View File

@ -3,13 +3,13 @@ use yazi_shared::{event::Exec, render};
use crate::tab::Tab;
impl Tab {
pub fn linemode(&mut self, e: &Exec) {
pub fn linemode(&mut self, mut e: Exec) {
render!(self.conf.patch(|c| {
let Some(mode) = e.args.first() else {
let Some(mode) = e.take_first() else {
return;
};
if !mode.is_empty() && mode.len() <= 20 {
c.linemode = mode.to_owned();
c.linemode = mode;
}
}));
}

View File

@ -7,10 +7,12 @@ pub struct Opt {
lock: PreviewLock,
}
impl TryFrom<&Exec> for Opt {
impl TryFrom<Exec> for Opt {
type Error = ();
fn try_from(e: &Exec) -> Result<Self, Self::Error> { Ok(Self { lock: e.take_data().ok_or(())? }) }
fn try_from(mut e: Exec) -> Result<Self, Self::Error> {
Ok(Self { lock: e.take_data().ok_or(())? })
}
}
impl Tab {

View File

@ -6,9 +6,9 @@ pub struct Opt {
target: Url,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self {
let mut target = Url::from(e.args.first().map(|s| s.as_str()).unwrap_or(""));
impl From<Exec> for Opt {
fn from(mut e: Exec) -> Self {
let mut target = Url::from(e.take_first().unwrap_or_default());
if target.is_regular() {
target.set_path(expand_path(&target))
}
@ -23,7 +23,7 @@ impl From<Url> for Opt {
impl Tab {
#[inline]
pub fn _reveal(target: &Url) {
emit!(Call(Exec::call("reveal", vec![target.to_string()]).vec(), Layer::Manager));
emit!(Call(Exec::call("reveal", vec![target.to_string()]), Layer::Manager));
}
pub fn reveal(&mut self, opt: impl Into<Opt>) {

View File

@ -16,9 +16,9 @@ pub enum OptType {
Fd,
}
impl From<&str> for OptType {
fn from(value: &str) -> Self {
match value {
impl From<String> for OptType {
fn from(value: String) -> Self {
match value.as_str() {
"rg" => Self::Rg,
"fd" => Self::Fd,
_ => Self::None,
@ -41,10 +41,8 @@ pub struct Opt {
pub type_: OptType,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self {
Self { type_: e.args.first().map(|s| s.as_str()).unwrap_or_default().into() }
}
impl From<Exec> for Opt {
fn from(mut e: Exec) -> Self { Self { type_: e.take_first().unwrap_or_default().into() } }
}
impl Tab {

View File

@ -6,8 +6,8 @@ pub struct Opt {
state: Option<bool>,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self {
impl From<Exec> for Opt {
fn from(e: Exec) -> Self {
Self {
state: match e.named.get("state").map(|s| s.as_str()) {
Some("true") => Some(true),

View File

@ -9,10 +9,10 @@ pub struct Opt {
confirm: bool,
}
impl<'a> From<&'a Exec> for Opt {
fn from(e: &'a Exec) -> Self {
impl From<Exec> for Opt {
fn from(mut e: Exec) -> Self {
Self {
cmd: e.args.first().map(|e| e.to_owned()).unwrap_or_default(),
cmd: e.take_first().unwrap_or_default(),
block: e.named.contains_key("block"),
confirm: e.named.contains_key("confirm"),
}

View File

@ -6,7 +6,7 @@ use yazi_shared::event::Exec;
use crate::{manager::Manager, tab::Tab, tasks::Tasks};
impl Tab {
pub fn sort(&mut self, e: &Exec, tasks: &Tasks) {
pub fn sort(&mut self, e: Exec, tasks: &Tasks) {
if let Some(by) = e.args.first() {
self.conf.sort_by = SortBy::from_str(by).unwrap_or_default();
}

View File

@ -8,8 +8,8 @@ pub struct Opt {
unset: bool,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self { Self { unset: e.named.contains_key("unset") } }
impl From<Exec> for Opt {
fn from(e: Exec) -> Self { Self { unset: e.named.contains_key("unset") } }
}
impl Tab {

View File

@ -6,9 +6,9 @@ pub struct Opt {
step: isize,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self {
Self { step: e.args.first().and_then(|s| s.parse().ok()).unwrap_or(0) }
impl From<Exec> for Opt {
fn from(mut e: Exec) -> Self {
Self { step: e.take_first().and_then(|s| s.parse().ok()).unwrap_or(0) }
}
}

View File

@ -3,7 +3,7 @@ use yazi_shared::{event::Exec, render};
use crate::tasks::Tasks;
impl Tasks {
pub fn cancel(&mut self, _: &Exec) {
pub fn cancel(&mut self, _: Exec) {
let id = self.scheduler.running.lock().get_id(self.cursor);
if id.map(|id| self.scheduler.cancel(id)) != Some(true) {
return;

View File

@ -8,7 +8,7 @@ use yazi_shared::{event::Exec, term::Term, Defer};
use crate::tasks::Tasks;
impl Tasks {
pub fn inspect(&self, _: &Exec) {
pub fn inspect(&self, _: Exec) {
let Some(id) = self.scheduler.running.lock().get_id(self.cursor) else {
return;
};

View File

@ -8,15 +8,15 @@ pub struct Opt {
opener: Opener,
}
impl TryFrom<&Exec> for Opt {
impl TryFrom<Exec> for Opt {
type Error = ();
fn try_from(e: &Exec) -> Result<Self, Self::Error> { e.take_data().ok_or(()) }
fn try_from(mut e: Exec) -> Result<Self, Self::Error> { e.take_data().ok_or(()) }
}
impl Tasks {
pub fn _open(targets: Vec<Url>, opener: Opener) {
emit!(Call(Exec::call("open", vec![]).with_data(Opt { targets, opener }).vec(), Layer::Tasks));
emit!(Call(Exec::call("open", vec![]).with_data(Opt { targets, opener }), Layer::Tasks));
}
pub fn open(&mut self, opt: impl TryInto<Opt>) {

View File

@ -4,8 +4,8 @@ use crate::tasks::Tasks;
pub struct Opt;
impl From<&Exec> for Opt {
fn from(_: &Exec) -> Self { Self }
impl From<Exec> for Opt {
fn from(_: Exec) -> Self { Self }
}
impl From<()> for Opt {
fn from(_: ()) -> Self { Self }

View File

@ -35,7 +35,7 @@ impl Tasks {
let new = TasksProgress::from(&*running.lock());
if last != new {
last = new;
emit!(Call(Exec::call("update_progress", vec![]).with_data(new).vec(), Layer::App));
emit!(Call(Exec::call("update_progress", vec![]).with_data(new), Layer::App));
}
}
});
@ -187,6 +187,7 @@ impl Tasks {
self.scheduler.preload_paged(rule, targets);
};
#[allow(clippy::needless_range_loop)]
for i in 0..PLUGIN.preloaders.len() {
if !multi_tasks[i].is_empty() {
go(&PLUGIN.preloaders[i], mem::take(&mut multi_tasks[i]));

View File

@ -36,10 +36,10 @@ impl Which {
self.visible = false;
} else if self.cands.len() == 1 {
self.visible = false;
emit!(Call(self.cands[0].to_call(), self.layer));
emit!(Seq(self.cands[0].to_seq(), self.layer));
} else if let Some(i) = self.cands.iter().position(|c| c.on.len() == self.times + 1) {
self.visible = false;
emit!(Call(self.cands[i].to_call(), self.layer));
emit!(Seq(self.cands[i].to_seq(), self.layer));
}
self.times += 1;

View File

@ -1,6 +1,6 @@
use std::{mem, sync::atomic::Ordering};
use std::{collections::VecDeque, mem, sync::atomic::Ordering};
use anyhow::{Ok, Result};
use anyhow::Result;
use crossterm::event::KeyEvent;
use yazi_config::keymap::Key;
use yazi_core::input::InputMode;
@ -25,12 +25,13 @@ impl App {
let mut app = Self { cx: Ctx::make(), term: Some(term), signals };
app.render()?;
let mut events = Vec::with_capacity(10);
let mut events = Vec::with_capacity(50);
let mut render_in_place = false;
while app.signals.rx.recv_many(&mut events, 10).await > 0 {
while app.signals.rx.recv_many(&mut events, 50).await > 0 {
for event in events.drain(..) {
match event {
Event::Call(exec, layer) => app.dispatch_call(exec, layer),
Event::Seq(execs, layer) => app.dispatch_seq(execs, layer),
Event::Render => render_in_place = true,
Event::Key(key) => app.dispatch_key(key),
Event::Resize => app.resize()?,
@ -43,7 +44,12 @@ impl App {
}
if mem::replace(&mut render_in_place, false) {
app.render()?;
if let Ok(event) = app.signals.rx.try_recv() {
events.push(event);
NEED_RENDER.store(true, Ordering::Relaxed);
} else {
app.render()?;
}
}
if NEED_RENDER.swap(false, Ordering::Relaxed) {
@ -66,7 +72,17 @@ impl App {
}
#[inline]
fn dispatch_call(&mut self, exec: Vec<Exec>, layer: Layer) {
Executor::new(self).dispatch(&exec, layer);
fn dispatch_call(&mut self, exec: Exec, layer: Layer) {
Executor::new(self).dispatch(exec, layer);
}
#[inline]
fn dispatch_seq(&mut self, mut execs: VecDeque<Exec>, layer: Layer) {
if let Some(exec) = execs.pop_front() {
Executor::new(self).dispatch(exec, layer);
}
if !execs.is_empty() {
emit!(Seq(execs, layer));
}
}
}

View File

@ -21,7 +21,7 @@ impl App {
tokio::spawn(async move {
if LOADED.ensure(&opt.name).await.is_ok() {
emit!(Call(Exec::call("plugin_do", vec![opt.name]).with_data(opt.data).vec(), Layer::App));
emit!(Call(Exec::call("plugin_do", vec![opt.name]).with_data(opt.data), Layer::App));
}
});
}

View File

@ -3,7 +3,7 @@ use yazi_shared::{event::Exec, term::Term};
use crate::app::App;
impl App {
pub(crate) fn resume(&mut self, _: &Exec) {
pub(crate) fn resume(&mut self, _: Exec) {
self.cx.manager.active_mut().preview.reset_image();
self.term = Some(Term::start().unwrap());

View File

@ -7,8 +7,8 @@ pub struct Opt {
tx: Option<oneshot::Sender<()>>,
}
impl From<&Exec> for Opt {
fn from(e: &Exec) -> Self { Self { tx: e.take_data() } }
impl From<Exec> for Opt {
fn from(mut e: Exec) -> Self { Self { tx: e.take_data() } }
}
impl App {

View File

@ -8,10 +8,10 @@ pub struct Opt {
progress: TasksProgress,
}
impl TryFrom<&Exec> for Opt {
impl TryFrom<Exec> for Opt {
type Error = ();
fn try_from(e: &Exec) -> Result<Self, Self::Error> {
fn try_from(mut e: Exec) -> Result<Self, Self::Error> {
Ok(Self { progress: e.take_data().ok_or(())? })
}
}

View File

@ -1,6 +1,6 @@
use yazi_config::{keymap::{Control, Key}, KEYMAP};
use yazi_core::input::InputMode;
use yazi_shared::{event::Exec, Layer};
use yazi_shared::{emit, event::Exec, Layer};
use crate::app::App;
@ -12,6 +12,20 @@ impl<'a> Executor<'a> {
#[inline]
pub(super) fn new(app: &'a mut App) -> Self { Self { app } }
#[inline]
pub(super) fn dispatch(&mut self, exec: Exec, layer: Layer) {
match layer {
Layer::App => self.app(exec),
Layer::Manager => self.manager(exec),
Layer::Tasks => self.tasks(exec),
Layer::Select => self.select(exec),
Layer::Input => self.input(exec),
Layer::Help => self.help(exec),
Layer::Completion => self.completion(exec),
Layer::Which => unreachable!(),
}
}
pub(super) fn handle(&mut self, key: Key) -> bool {
let cx = &mut self.app.cx;
@ -42,7 +56,7 @@ impl<'a> Executor<'a> {
#[inline]
fn matches(&mut self, layer: Layer, key: Key) -> bool {
for Control { on, exec, .. } in KEYMAP.get(layer) {
for ctrl @ Control { on, .. } in KEYMAP.get(layer) {
if on.is_empty() || on[0] != key {
continue;
}
@ -50,30 +64,14 @@ impl<'a> Executor<'a> {
if on.len() > 1 {
self.app.cx.which.show(&key, layer);
} else {
self.dispatch(exec, layer);
emit!(Seq(ctrl.to_seq(), layer));
}
return true;
}
false
}
#[inline]
pub(super) fn dispatch(&mut self, exec: &[Exec], layer: Layer) {
for e in exec {
match layer {
Layer::App => self.app(e),
Layer::Manager => self.manager(e),
Layer::Tasks => self.tasks(e),
Layer::Select => self.select(e),
Layer::Input => self.input(e),
Layer::Help => self.help(e),
Layer::Completion => self.completion(e),
Layer::Which => unreachable!(),
};
}
}
fn app(&mut self, exec: &Exec) {
fn app(&mut self, exec: Exec) {
macro_rules! on {
($name:ident) => {
if exec.cmd == stringify!($name) {
@ -89,7 +87,7 @@ impl<'a> Executor<'a> {
on!(resume);
}
fn manager(&mut self, exec: &Exec) {
fn manager(&mut self, exec: Exec) {
macro_rules! on {
(MANAGER, $name:ident $(,$args:expr)*) => {
if exec.cmd == stringify!($name) {
@ -180,7 +178,7 @@ impl<'a> Executor<'a> {
}
}
fn tasks(&mut self, exec: &Exec) {
fn tasks(&mut self, exec: Exec) {
macro_rules! on {
($name:ident) => {
if exec.cmd == stringify!($name) {
@ -200,13 +198,14 @@ impl<'a> Executor<'a> {
on!(inspect);
on!(cancel);
#[allow(clippy::single_match)]
match exec.cmd.as_str() {
"help" => self.app.cx.help.toggle(Layer::Tasks),
_ => {}
}
}
fn select(&mut self, exec: &Exec) {
fn select(&mut self, exec: Exec) {
macro_rules! on {
($name:ident) => {
if exec.cmd == stringify!($name) {
@ -219,13 +218,14 @@ impl<'a> Executor<'a> {
on!(close);
on!(arrow);
#[allow(clippy::single_match)]
match exec.cmd.as_str() {
"help" => self.app.cx.help.toggle(Layer::Select),
_ => {}
}
}
fn input(&mut self, exec: &Exec) {
fn input(&mut self, exec: Exec) {
macro_rules! on {
($name:ident) => {
if exec.cmd == stringify!($name) {
@ -266,6 +266,7 @@ impl<'a> Executor<'a> {
on!(undo);
on!(redo);
#[allow(clippy::single_match)]
match exec.cmd.as_str() {
"help" => self.app.cx.help.toggle(Layer::Input),
_ => {}
@ -278,7 +279,7 @@ impl<'a> Executor<'a> {
}
}
fn help(&mut self, exec: &Exec) {
fn help(&mut self, exec: Exec) {
macro_rules! on {
($name:ident) => {
if exec.cmd == stringify!($name) {
@ -291,13 +292,14 @@ impl<'a> Executor<'a> {
on!(arrow);
on!(filter);
#[allow(clippy::single_match)]
match exec.cmd.as_str() {
"close" => self.app.cx.help.toggle(Layer::Help),
_ => {}
}
}
fn completion(&mut self, exec: &Exec) {
fn completion(&mut self, exec: Exec) {
macro_rules! on {
($name:ident) => {
if exec.cmd == stringify!($name) {
@ -311,6 +313,7 @@ impl<'a> Executor<'a> {
on!(close);
on!(arrow);
#[allow(clippy::single_match)]
match exec.cmd.as_str() {
"help" => self.app.cx.help.toggle(Layer::Completion),
_ => {}

View File

@ -21,6 +21,7 @@ use context::*;
use executor::*;
use logs::*;
use panic::*;
#[allow(unused_imports)]
use root::*;
use signals::*;

View File

@ -8,6 +8,7 @@ mod range;
mod url;
mod window;
#[allow(unused_imports)]
pub use bindings::*;
pub use cha::*;
pub use file::*;

View File

@ -68,7 +68,7 @@ pub fn peek_sync(exec: &Exec, file: yazi_shared::fs::File, skip: usize) {
tx: None,
};
emit!(Call(
Exec::call("plugin", vec![exec.cmd.to_owned()]).with_bool("sync", true).with_data(data).vec(),
Exec::call("plugin", vec![exec.cmd.to_owned()]).with_bool("sync", true).with_data(data),
Layer::App
));
}

View File

@ -15,7 +15,7 @@ pub fn seek_sync(exec: &Exec, file: yazi_shared::fs::File, units: i16) {
tx: None,
};
emit!(Call(
Exec::call("plugin", vec![exec.cmd.to_owned()]).with_bool("sync", true).with_data(data).vec(),
Exec::call("plugin", vec![exec.cmd.to_owned()]).with_bool("sync", true).with_data(data),
Layer::App
));
}

View File

@ -18,18 +18,14 @@ pub struct OptData {
pub tx: Option<oneshot::Sender<ValueSendable>>,
}
impl TryFrom<&Exec> for Opt {
impl TryFrom<Exec> for Opt {
type Error = anyhow::Error;
fn try_from(e: &Exec) -> Result<Self, Self::Error> {
let Some(name) = e.args.first().filter(|s| !s.is_empty()) else {
fn try_from(mut e: Exec) -> Result<Self, Self::Error> {
let Some(name) = e.take_first().filter(|s| !s.is_empty()) else {
bail!("invalid plugin name");
};
Ok(Self {
name: name.to_owned(),
sync: e.named.contains_key("sync"),
data: e.take_data().unwrap_or_default(),
})
Ok(Self { name, sync: e.named.contains_key("sync"), data: e.take_data().unwrap_or_default() })
}
}

View File

@ -48,7 +48,7 @@ impl Utils {
exec = exec.with_data(data);
}
emit!(Call(exec.vec(), Layer::Manager));
emit!(Call(exec, Layer::Manager));
Ok(())
},
)?,

View File

@ -44,7 +44,7 @@ impl Utils {
};
lock.data = vec![Box::new(Paragraph { area: *area, text, ..Default::default() })];
emit!(Call(Exec::call("preview", vec![]).with_data(lock).vec(), Layer::Manager));
emit!(Call(Exec::call("preview", vec![]).with_data(lock), Layer::Manager));
(true, Value::Nil).into_lua_multi(lua)
})?,
)?;
@ -67,7 +67,7 @@ impl Utils {
..Default::default()
})];
emit!(Call(Exec::call("preview", vec![]).with_data(lock).vec(), Layer::Manager));
emit!(Call(Exec::call("preview", vec![]).with_data(lock), Layer::Manager));
(true, Value::Nil).into_lua_multi(lua)
})?,
)?;
@ -78,7 +78,7 @@ impl Utils {
let mut lock = PreviewLock::try_from(t)?;
lock.data = widgets.into_iter().filter_map(cast_to_renderable).collect();
emit!(Call(Exec::call("preview", vec![]).with_data(lock).vec(), Layer::Manager));
emit!(Call(Exec::call("preview", vec![]).with_data(lock), Layer::Manager));
Ok(())
})?,
)?;

View File

@ -164,12 +164,12 @@ impl Scheduler {
pub async fn app_stop() {
let (tx, rx) = oneshot::channel::<()>();
emit!(Call(Exec::call("stop", vec![]).with_data(tx).vec(), Layer::App));
emit!(Call(Exec::call("stop", vec![]).with_data(tx), Layer::App));
rx.await.ok();
}
pub fn app_resume() {
emit!(Call(Exec::call("resume", vec![]).vec(), Layer::App));
emit!(Call(Exec::call("resume", vec![]), Layer::App));
}
pub fn file_cut(&self, from: Url, mut to: Url, force: bool) {

View File

@ -1,4 +1,4 @@
use std::ffi::OsString;
use std::{collections::VecDeque, ffi::OsString};
use crossterm::event::KeyEvent;
use tokio::sync::{mpsc, oneshot};
@ -10,7 +10,8 @@ static TX: RoCell<mpsc::UnboundedSender<Event>> = RoCell::new();
#[derive(Debug)]
pub enum Event {
Call(Vec<Exec>, Layer),
Call(Exec, Layer),
Seq(VecDeque<Exec>, Layer),
Render,
Key(KeyEvent),
Resize,
@ -46,6 +47,9 @@ macro_rules! emit {
(Call($exec:expr, $layer:expr)) => {
$crate::event::Event::Call($exec, $layer).emit();
};
(Seq($execs:expr, $layer:expr)) => {
$crate::event::Event::Seq($execs, $layer).emit();
};
($event:ident) => {
$crate::event::Event::$event.emit();
};

View File

@ -1,11 +1,11 @@
use std::{any::Any, cell::RefCell, collections::BTreeMap, fmt::{self, Display}};
use std::{any::Any, collections::BTreeMap, fmt::{self, Display}, mem};
#[derive(Debug, Default)]
pub struct Exec {
pub cmd: String,
pub args: Vec<String>,
pub named: BTreeMap<String, String>,
pub data: RefCell<Option<Box<dyn Any + Send>>>,
pub data: Option<Box<dyn Any + Send>>,
}
impl Exec {
@ -19,9 +19,6 @@ impl Exec {
Exec { cmd: cwd.to_owned(), named, ..Default::default() }
}
#[inline]
pub fn vec(self) -> Vec<Self> { vec![self] }
#[inline]
pub fn with(mut self, name: impl ToString, value: impl ToString) -> Self {
self.named.insert(name.to_string(), value.to_string());
@ -38,13 +35,31 @@ impl Exec {
#[inline]
pub fn with_data(mut self, data: impl Any + Send) -> Self {
self.data = RefCell::new(Some(Box::new(data)));
self.data = Some(Box::new(data));
self
}
#[inline]
pub fn take_data<T: 'static>(&self) -> Option<T> {
self.data.replace(None).and_then(|d| d.downcast::<T>().ok()).map(|d| *d)
pub fn take_data<T: 'static>(&mut self) -> Option<T> {
self.data.take().and_then(|d| d.downcast::<T>().ok()).map(|d| *d)
}
#[inline]
pub fn take_first(&mut self) -> Option<String> {
if self.args.is_empty() { None } else { Some(mem::take(&mut self.args[0])) }
}
#[inline]
pub fn take_name(&mut self, name: &str) -> Option<String> { self.named.remove(name) }
#[inline]
pub fn clone_without_data(&self) -> Self {
Self {
cmd: self.cmd.clone(),
args: self.args.clone(),
named: self.named.clone(),
..Default::default()
}
}
}

View File

@ -36,7 +36,7 @@ impl FilesOp {
#[inline]
pub fn emit(self) {
emit!(Call(Exec::call("update_files", vec![]).with_data(self).vec(), Layer::Manager));
emit!(Call(Exec::call("update_files", vec![]).with_data(self), Layer::Manager));
}
pub fn prepare(url: &Url) -> u64 {