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

View file

@ -6,9 +6,9 @@ pub struct Opt {
step: isize, step: isize,
} }
impl From<&Exec> for Opt { impl From<Exec> for Opt {
fn from(e: &Exec) -> Self { fn from(mut e: Exec) -> Self {
Self { step: e.args.first().and_then(|s| s.parse().ok()).unwrap_or(0) } 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, submit: bool,
} }
impl From<&Exec> for Opt { impl From<Exec> for Opt {
fn from(e: &Exec) -> Self { Self { submit: e.named.contains_key("submit") } } fn from(e: Exec) -> Self { Self { submit: e.named.contains_key("submit") } }
} }
impl Completion { impl Completion {
#[inline] #[inline]
pub fn _close() { 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>) { pub fn close(&mut self, opt: impl Into<Opt>) {
let opt = opt.into() as 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(); self.caches.clear();

View file

@ -6,20 +6,20 @@ use crate::completion::Completion;
const LIMIT: usize = 30; const LIMIT: usize = 30;
pub struct Opt<'a> { pub struct Opt {
cache: &'a Vec<String>, cache: Vec<String>,
cache_name: &'a str, cache_name: String,
word: &'a str, word: String,
ticket: usize, ticket: usize,
} }
impl<'a> From<&'a Exec> for Opt<'a> { impl From<Exec> for Opt {
fn from(e: &'a Exec) -> Self { fn from(mut e: Exec) -> Self {
Self { Self {
cache: &e.args, cache: mem::take(&mut e.args),
cache_name: e.named.get("cache-name").map(|n| n.as_str()).unwrap_or_default(), cache_name: e.take_name("cache-name").unwrap_or_default(),
word: e.named.get("word").map(|w| w.as_str()).unwrap_or_default(), word: e.take_name("word").unwrap_or_default(),
ticket: e.named.get("ticket").and_then(|v| v.parse().ok()).unwrap_or(0), 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() 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; let opt = opt.into() as Opt;
if self.ticket != opt.ticket { if self.ticket != opt.ticket {
return; return;
@ -63,12 +63,12 @@ impl Completion {
if !opt.cache.is_empty() { if !opt.cache.is_empty() {
self.caches.insert(opt.cache_name.to_owned(), opt.cache.clone()); 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; return;
}; };
self.ticket = opt.ticket; 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() { if self.cands.is_empty() {
return render!(mem::replace(&mut self.visible, false)); 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; use crate::completion::Completion;
pub struct Opt<'a> { pub struct Opt {
word: &'a str, word: String,
ticket: usize, ticket: usize,
} }
impl<'a> From<&'a Exec> for Opt<'a> { impl From<Exec> for Opt {
fn from(e: &'a Exec) -> Self { fn from(mut e: Exec) -> Self {
Self { Self {
word: e.args.first().map(|s| s.as_str()).unwrap_or_default(), word: e.take_first().unwrap_or_default(),
ticket: e.named.get("ticket").and_then(|s| s.parse().ok()).unwrap_or(0), ticket: e.take_name("ticket").and_then(|s| s.parse().ok()).unwrap_or(0),
} }
} }
} }
@ -23,23 +23,23 @@ impl Completion {
#[inline] #[inline]
pub fn _trigger(word: &str, ticket: usize) { pub fn _trigger(word: &str, ticket: usize) {
emit!(Call( 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 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; let opt = opt.into() as Opt;
if opt.ticket < self.ticket { if opt.ticket < self.ticket {
return; return;
} }
self.ticket = opt.ticket; 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) { if self.caches.contains_key(&parent) {
return self.show( return self.show(
&Exec::call("show", vec![]) Exec::call("show", vec![])
.with("cache-name", parent) .with("cache-name", parent)
.with("word", child) .with("word", child)
.with("ticket", opt.ticket), .with("ticket", opt.ticket),
@ -67,8 +67,7 @@ impl Completion {
Exec::call("show", cache) Exec::call("show", cache)
.with("cache-name", parent) .with("cache-name", parent)
.with("word", child) .with("word", child)
.with("ticket", ticket) .with("ticket", ticket),
.vec(),
Layer::Completion Layer::Completion
)); ));
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -8,10 +8,10 @@ pub struct Opt {
in_operating: bool, in_operating: bool,
} }
impl From<&Exec> for Opt { impl From<Exec> for Opt {
fn from(e: &Exec) -> Self { fn from(mut e: Exec) -> Self {
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"), in_operating: e.named.contains_key("in-operating"),
} }
} }

View file

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

View file

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

View file

@ -9,16 +9,16 @@ pub struct Opt {
tx: mpsc::UnboundedSender<Result<String, InputError>>, tx: mpsc::UnboundedSender<Result<String, InputError>>,
} }
impl TryFrom<&Exec> for Opt { impl TryFrom<Exec> for Opt {
type Error = (); 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 { impl Input {
pub fn _show(cfg: InputCfg) -> mpsc::UnboundedReceiver<Result<String, InputError>> { pub fn _show(cfg: InputCfg) -> mpsc::UnboundedReceiver<Result<String, InputError>> {
let (tx, rx) = mpsc::unbounded_channel(); 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 rx
} }

View file

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

View file

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

View file

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

View file

@ -3,7 +3,7 @@ use yazi_shared::{event::Exec, render};
use crate::input::{op::InputOp, Input}; use crate::input::{op::InputOp, Input};
impl Input { impl Input {
pub fn yank(&mut self, _: &Exec) { pub fn yank(&mut self, _: Exec) {
match self.snap().op { match self.snap().op {
InputOp::None => { InputOp::None => {
self.snap_mut().op = InputOp::Yank(self.snap().cursor); 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}; use crate::{manager::Manager, tasks::Tasks};
impl Manager { impl Manager {
pub fn close(&mut self, _: &Exec, tasks: &Tasks) { pub fn close(&mut self, _: Exec, tasks: &Tasks) {
if self.tabs.len() > 1 { if self.tabs.len() > 1 {
return self.tabs.close(self.tabs.idx); return self.tabs.close(self.tabs.idx);
} }

View file

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

View file

@ -8,8 +8,8 @@ pub struct Opt {
url: Option<Url>, url: Option<Url>,
} }
impl From<&Exec> for Opt { impl From<Exec> for Opt {
fn from(e: &Exec) -> Self { Self { url: e.args.first().map(Url::from) } } fn from(mut e: Exec) -> Self { Self { url: e.take_first().map(Url::from) } }
} }
impl From<Option<Url>> for Opt { impl From<Option<Url>> for Opt {
fn from(url: Option<Url>) -> Self { Self { url } } fn from(url: Option<Url>) -> Self { Self { url } }
@ -19,7 +19,7 @@ impl Manager {
#[inline] #[inline]
pub fn _hover(url: Option<Url>) { pub fn _hover(url: Option<Url>) {
emit!(Call( 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 Layer::Manager
)); ));
} }

View file

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

View file

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

View file

@ -7,8 +7,8 @@ pub struct Opt {
follow: bool, follow: bool,
} }
impl From<&Exec> for Opt { impl From<Exec> for Opt {
fn from(e: &Exec) -> Self { fn from(e: Exec) -> Self {
Self { force: e.named.contains_key("force"), follow: e.named.contains_key("follow") } 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, upper_bound: bool,
} }
impl From<&Exec> for Opt { impl From<Exec> for Opt {
fn from(e: &Exec) -> Self { fn from(mut e: Exec) -> Self {
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"), 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"), upper_bound: e.named.contains_key("upper-bound"),
} }
} }
@ -27,7 +27,7 @@ impl From<bool> for Opt {
impl Manager { impl Manager {
#[inline] #[inline]
pub fn _peek(force: bool) { 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>) { pub fn peek(&mut self, opt: impl Into<Opt>) {

View file

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

View file

@ -7,10 +7,10 @@ use crate::{manager::Manager, tasks::Tasks};
impl Manager { impl Manager {
#[inline] #[inline]
pub fn _refresh() { 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_current_dir(self.cwd()).ok();
env::set_var("PWD", self.cwd()); env::set_var("PWD", self.cwd());

View file

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

View file

@ -9,9 +9,9 @@ pub struct Opt {
units: i16, units: i16,
} }
impl From<&Exec> for Opt { impl From<Exec> for Opt {
fn from(e: &Exec) -> Self { fn from(mut e: Exec) -> Self {
Self { units: e.args.first().and_then(|s| s.parse().ok()).unwrap_or(0) } 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; use crate::manager::Manager;
impl Manager { impl Manager {
pub fn suspend(&mut self, _: &Exec) { pub fn suspend(&mut self, _: Exec) {
#[cfg(unix)] #[cfg(unix)]
tokio::spawn(async move { tokio::spawn(async move {
Scheduler::app_stop().await; Scheduler::app_stop().await;

View file

@ -6,9 +6,9 @@ pub struct Opt {
idx: usize, idx: usize,
} }
impl From<&Exec> for Opt { impl From<Exec> for Opt {
fn from(e: &Exec) -> Self { fn from(mut e: Exec) -> Self {
Self { idx: e.args.first().and_then(|i| i.parse().ok()).unwrap_or(0) } 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, current: bool,
} }
impl From<&Exec> for Opt { impl From<Exec> for Opt {
fn from(e: &Exec) -> Self { fn from(mut e: Exec) -> Self {
let mut opt = Self { url: None, current: e.named.contains_key("current") }; let mut opt = Self { url: None, current: e.named.contains_key("current") };
if !opt.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 opt
} }

View file

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

View file

@ -8,10 +8,12 @@ pub struct Opt {
op: FilesOp, op: FilesOp,
} }
impl TryFrom<&Exec> for Opt { impl TryFrom<Exec> for Opt {
type Error = (); 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 { impl Manager {

View file

@ -9,10 +9,12 @@ pub struct Opt {
data: ValueSendable, data: ValueSendable,
} }
impl TryFrom<&Exec> for Opt { impl TryFrom<Exec> for Opt {
type Error = (); 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 { impl Manager {

View file

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

View file

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

View file

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

View file

@ -10,16 +10,16 @@ pub struct Opt {
tx: oneshot::Sender<Result<usize>>, tx: oneshot::Sender<Result<usize>>,
} }
impl TryFrom<&Exec> for Opt { impl TryFrom<Exec> for Opt {
type Error = (); 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 { impl Select {
pub async fn _show(cfg: SelectCfg) -> Result<usize> { pub async fn _show(cfg: SelectCfg) -> Result<usize> {
let (tx, rx) = oneshot::channel(); 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)) rx.await.unwrap_or_else(|_| Term::goodbye(|| false))
} }

View file

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

View file

@ -12,9 +12,9 @@ pub struct Opt {
interactive: bool, interactive: bool,
} }
impl From<&Exec> for Opt { impl From<Exec> for Opt {
fn from(e: &Exec) -> Self { fn from(mut e: Exec) -> Self {
let mut target = Url::from(e.args.first().map(|s| s.as_str()).unwrap_or("")); let mut target = Url::from(e.take_first().unwrap_or_default());
if target.is_regular() { if target.is_regular() {
target.set_path(expand_path(&target)) target.set_path(expand_path(&target))
} }
@ -29,7 +29,7 @@ impl From<Url> for Opt {
impl Tab { impl Tab {
#[inline] #[inline]
pub fn _cd(target: &Url) { 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>) { 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}; use crate::{tab::Tab, CLIPBOARD};
pub struct Opt<'a> { pub struct Opt {
type_: &'a str, type_: String,
} }
impl<'a> From<&'a Exec> for Opt<'a> { impl From<Exec> for Opt {
fn from(e: &'a Exec) -> Self { Self { type_: e.args.first().map(|s| s.as_str()).unwrap_or("") } } fn from(mut e: Exec) -> Self { Self { type_: e.take_first().unwrap_or_default() } }
} }
impl Tab { 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 opt = opt.into() as Opt;
let mut s = OsString::new(); let mut s = OsString::new();
let mut it = self.selected().into_iter().peekable(); let mut it = self.selected().into_iter().peekable();
while let Some(f) = it.next() { while let Some(f) = it.next() {
s.push(match opt.type_ { s.push(match opt.type_.as_str() {
"path" => f.url.as_os_str(), "path" => f.url.as_os_str(),
"dirname" => f.url.parent().map_or(OsStr::new(""), |p| p.as_os_str()), "dirname" => f.url.parent().map_or(OsStr::new(""), |p| p.as_os_str()),
"filename" => f.name().unwrap_or(OsStr::new("")), "filename" => f.name().unwrap_or(OsStr::new("")),

View file

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

View file

@ -13,15 +13,15 @@ bitflags! {
} }
} }
impl From<&Exec> for Opt { impl From<Exec> for Opt {
fn from(e: &Exec) -> Self { fn from(e: Exec) -> Self {
e.named.iter().fold(Opt::empty(), |acc, (k, _)| match k.as_bytes() { e.named.iter().fold(Opt::empty(), |acc, (k, _)| match k.as_str() {
b"all" => Self::all(), "all" => Self::all(),
b"find" => acc | Self::FIND, "find" => acc | Self::FIND,
b"visual" => acc | Self::VISUAL, "visual" => acc | Self::VISUAL,
b"select" => acc | Self::SELECT, "select" => acc | Self::SELECT,
b"filter" => acc | Self::FILTER, "filter" => acc | Self::FILTER,
b"search" => acc | Self::SEARCH, "search" => acc | Self::SEARCH,
_ => acc, _ => acc,
}) })
} }
@ -47,7 +47,7 @@ impl Tab {
#[inline] #[inline]
fn escape_filter(&mut self) -> bool { fn escape_filter(&mut self) -> bool {
let b = self.current.files.filter().is_some(); 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 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}; use crate::{folder::{Filter, FilterCase}, input::Input, manager::Manager, tab::Tab};
#[derive(Default)] #[derive(Default)]
pub struct Opt<'a> { pub struct Opt {
pub query: &'a str, pub query: String,
pub case: FilterCase, pub case: FilterCase,
pub done: bool, pub done: bool,
} }
impl<'a> From<&'a Exec> for Opt<'a> { impl From<Exec> for Opt {
fn from(e: &'a Exec) -> Self { fn from(mut e: Exec) -> Self {
Self { Self {
query: e.args.first().map(|s| s.as_str()).unwrap_or_default(), query: e.take_first().unwrap_or_default(),
case: e.into(), case: FilterCase::from(&e),
done: e.named.contains_key("done"), done: e.named.contains_key("done"),
} }
} }
} }
impl Tab { 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; let opt = opt.into() as Opt;
tokio::spawn(async move { tokio::spawn(async move {
let rx = Input::_show(InputCfg::filter()); let rx = Input::_show(InputCfg::filter());
@ -43,20 +43,19 @@ impl Tab {
Exec::call("filter_do", vec![s]) Exec::call("filter_do", vec![s])
.with_bool("smart", opt.case == FilterCase::Smart) .with_bool("smart", opt.case == FilterCase::Smart)
.with_bool("insensitive", opt.case == FilterCase::Insensitive) .with_bool("insensitive", opt.case == FilterCase::Insensitive)
.with_bool("done", done) .with_bool("done", done),
.vec(),
Layer::Manager 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 opt = opt.into() as Opt;
let filter = if opt.query.is_empty() { let filter = if opt.query.is_empty() {
None 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) Some(f)
} else { } else {
return; 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}}; use crate::{folder::FilterCase, input::Input, tab::{Finder, Tab}};
pub struct Opt<'a> { pub struct Opt {
query: Option<&'a str>, query: Option<String>,
prev: bool, prev: bool,
case: FilterCase, case: FilterCase,
} }
impl<'a> From<&'a Exec> for Opt<'a> { impl From<Exec> for Opt {
fn from(e: &'a Exec) -> Self { fn from(mut e: Exec) -> Self {
Self { Self {
query: e.args.first().map(|s| s.as_str()), query: e.take_first(),
prev: e.named.contains_key("previous"), prev: e.named.contains_key("previous"),
case: e.into(), case: FilterCase::from(&e),
} }
} }
} }
@ -27,12 +27,12 @@ pub struct ArrowOpt {
prev: bool, prev: bool,
} }
impl From<&Exec> for ArrowOpt { impl From<Exec> for ArrowOpt {
fn from(e: &Exec) -> Self { Self { prev: e.named.contains_key("previous") } } fn from(e: Exec) -> Self { Self { prev: e.named.contains_key("previous") } }
} }
impl Tab { 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; let opt = opt.into() as Opt;
tokio::spawn(async move { tokio::spawn(async move {
let rx = Input::_show(InputCfg::find(opt.prev)); let rx = Input::_show(InputCfg::find(opt.prev));
@ -45,15 +45,14 @@ impl Tab {
Exec::call("find_do", vec![s]) Exec::call("find_do", vec![s])
.with_bool("previous", opt.prev) .with_bool("previous", opt.prev)
.with_bool("smart", opt.case == FilterCase::Smart) .with_bool("smart", opt.case == FilterCase::Smart)
.with_bool("insensitive", opt.case == FilterCase::Insensitive) .with_bool("insensitive", opt.case == FilterCase::Insensitive),
.vec(),
Layer::Manager 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 opt = opt.into() as Opt;
let Some(query) = opt.query else { let Some(query) = opt.query else {
return; return;
@ -62,7 +61,7 @@ impl Tab {
return self.escape(super::escape::Opt::FIND); 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; return;
}; };
if matches!(&self.finder, Some(f) if f.filter == finder.filter) { 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}; use crate::{manager::Manager, tab::Tab};
impl Tab { impl Tab {
pub fn hidden(&mut self, e: &Exec) { pub fn hidden(&mut self, e: Exec) {
self.conf.show_hidden = match e.args.first().map(|s| s.as_bytes()) { self.conf.show_hidden = match e.args.first().map(|s| s.as_str()) {
Some(b"show") => true, Some("show") => true,
Some(b"hide") => false, Some("hide") => false,
_ => !self.conf.show_hidden, _ => !self.conf.show_hidden,
}; };

View file

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

View file

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

View file

@ -3,13 +3,13 @@ use yazi_shared::{event::Exec, render};
use crate::tab::Tab; use crate::tab::Tab;
impl Tab { impl Tab {
pub fn linemode(&mut self, e: &Exec) { pub fn linemode(&mut self, mut e: Exec) {
render!(self.conf.patch(|c| { render!(self.conf.patch(|c| {
let Some(mode) = e.args.first() else { let Some(mode) = e.take_first() else {
return; return;
}; };
if !mode.is_empty() && mode.len() <= 20 { 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, lock: PreviewLock,
} }
impl TryFrom<&Exec> for Opt { impl TryFrom<Exec> for Opt {
type Error = (); 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 { impl Tab {

View file

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

View file

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

View file

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

View file

@ -9,10 +9,10 @@ pub struct Opt {
confirm: bool, confirm: bool,
} }
impl<'a> From<&'a Exec> for Opt { impl From<Exec> for Opt {
fn from(e: &'a Exec) -> Self { fn from(mut e: Exec) -> Self {
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"), block: e.named.contains_key("block"),
confirm: e.named.contains_key("confirm"), 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}; use crate::{manager::Manager, tab::Tab, tasks::Tasks};
impl Tab { 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() { if let Some(by) = e.args.first() {
self.conf.sort_by = SortBy::from_str(by).unwrap_or_default(); self.conf.sort_by = SortBy::from_str(by).unwrap_or_default();
} }

View file

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

View file

@ -6,9 +6,9 @@ pub struct Opt {
step: isize, step: isize,
} }
impl From<&Exec> for Opt { impl From<Exec> for Opt {
fn from(e: &Exec) -> Self { fn from(mut e: Exec) -> Self {
Self { step: e.args.first().and_then(|s| s.parse().ok()).unwrap_or(0) } 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; use crate::tasks::Tasks;
impl 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); let id = self.scheduler.running.lock().get_id(self.cursor);
if id.map(|id| self.scheduler.cancel(id)) != Some(true) { if id.map(|id| self.scheduler.cancel(id)) != Some(true) {
return; return;

View file

@ -8,7 +8,7 @@ use yazi_shared::{event::Exec, term::Term, Defer};
use crate::tasks::Tasks; use crate::tasks::Tasks;
impl 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 { let Some(id) = self.scheduler.running.lock().get_id(self.cursor) else {
return; return;
}; };

View file

@ -8,15 +8,15 @@ pub struct Opt {
opener: Opener, opener: Opener,
} }
impl TryFrom<&Exec> for Opt { impl TryFrom<Exec> for Opt {
type Error = (); 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 { impl Tasks {
pub fn _open(targets: Vec<Url>, opener: Opener) { 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>) { pub fn open(&mut self, opt: impl TryInto<Opt>) {

View file

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

View file

@ -35,7 +35,7 @@ impl Tasks {
let new = TasksProgress::from(&*running.lock()); let new = TasksProgress::from(&*running.lock());
if last != new { if last != new {
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); self.scheduler.preload_paged(rule, targets);
}; };
#[allow(clippy::needless_range_loop)]
for i in 0..PLUGIN.preloaders.len() { for i in 0..PLUGIN.preloaders.len() {
if !multi_tasks[i].is_empty() { if !multi_tasks[i].is_empty() {
go(&PLUGIN.preloaders[i], mem::take(&mut multi_tasks[i])); go(&PLUGIN.preloaders[i], mem::take(&mut multi_tasks[i]));

View file

@ -36,10 +36,10 @@ impl Which {
self.visible = false; self.visible = false;
} else if self.cands.len() == 1 { } else if self.cands.len() == 1 {
self.visible = false; 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) { } else if let Some(i) = self.cands.iter().position(|c| c.on.len() == self.times + 1) {
self.visible = false; self.visible = false;
emit!(Call(self.cands[i].to_call(), self.layer)); emit!(Seq(self.cands[i].to_seq(), self.layer));
} }
self.times += 1; 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 crossterm::event::KeyEvent;
use yazi_config::keymap::Key; use yazi_config::keymap::Key;
use yazi_core::input::InputMode; use yazi_core::input::InputMode;
@ -25,12 +25,13 @@ impl App {
let mut app = Self { cx: Ctx::make(), term: Some(term), signals }; let mut app = Self { cx: Ctx::make(), term: Some(term), signals };
app.render()?; app.render()?;
let mut events = Vec::with_capacity(10); let mut events = Vec::with_capacity(50);
let mut render_in_place = false; 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(..) { for event in events.drain(..) {
match event { match event {
Event::Call(exec, layer) => app.dispatch_call(exec, layer), 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::Render => render_in_place = true,
Event::Key(key) => app.dispatch_key(key), Event::Key(key) => app.dispatch_key(key),
Event::Resize => app.resize()?, Event::Resize => app.resize()?,
@ -43,7 +44,12 @@ impl App {
} }
if mem::replace(&mut render_in_place, false) { 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) { if NEED_RENDER.swap(false, Ordering::Relaxed) {
@ -66,7 +72,17 @@ impl App {
} }
#[inline] #[inline]
fn dispatch_call(&mut self, exec: Vec<Exec>, layer: Layer) { fn dispatch_call(&mut self, exec: Exec, layer: Layer) {
Executor::new(self).dispatch(&exec, 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 { tokio::spawn(async move {
if LOADED.ensure(&opt.name).await.is_ok() { 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; use crate::app::App;
impl 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.cx.manager.active_mut().preview.reset_image();
self.term = Some(Term::start().unwrap()); self.term = Some(Term::start().unwrap());

View file

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

View file

@ -8,10 +8,10 @@ pub struct Opt {
progress: TasksProgress, progress: TasksProgress,
} }
impl TryFrom<&Exec> for Opt { impl TryFrom<Exec> for Opt {
type Error = (); 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(())? }) Ok(Self { progress: e.take_data().ok_or(())? })
} }
} }

View file

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

View file

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

View file

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

View file

@ -68,7 +68,7 @@ pub fn peek_sync(exec: &Exec, file: yazi_shared::fs::File, skip: usize) {
tx: None, tx: None,
}; };
emit!(Call( 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 Layer::App
)); ));
} }

View file

@ -15,7 +15,7 @@ pub fn seek_sync(exec: &Exec, file: yazi_shared::fs::File, units: i16) {
tx: None, tx: None,
}; };
emit!(Call( 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 Layer::App
)); ));
} }

View file

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

View file

@ -44,7 +44,7 @@ impl Utils {
}; };
lock.data = vec![Box::new(Paragraph { area: *area, text, ..Default::default() })]; 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) (true, Value::Nil).into_lua_multi(lua)
})?, })?,
)?; )?;
@ -67,7 +67,7 @@ impl Utils {
..Default::default() ..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) (true, Value::Nil).into_lua_multi(lua)
})?, })?,
)?; )?;
@ -78,7 +78,7 @@ impl Utils {
let mut lock = PreviewLock::try_from(t)?; let mut lock = PreviewLock::try_from(t)?;
lock.data = widgets.into_iter().filter_map(cast_to_renderable).collect(); 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(()) Ok(())
})?, })?,
)?; )?;

View file

@ -164,12 +164,12 @@ impl Scheduler {
pub async fn app_stop() { pub async fn app_stop() {
let (tx, rx) = oneshot::channel::<()>(); 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(); rx.await.ok();
} }
pub fn app_resume() { 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) { 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 crossterm::event::KeyEvent;
use tokio::sync::{mpsc, oneshot}; use tokio::sync::{mpsc, oneshot};
@ -10,7 +10,8 @@ static TX: RoCell<mpsc::UnboundedSender<Event>> = RoCell::new();
#[derive(Debug)] #[derive(Debug)]
pub enum Event { pub enum Event {
Call(Vec<Exec>, Layer), Call(Exec, Layer),
Seq(VecDeque<Exec>, Layer),
Render, Render,
Key(KeyEvent), Key(KeyEvent),
Resize, Resize,
@ -46,6 +47,9 @@ macro_rules! emit {
(Call($exec:expr, $layer:expr)) => { (Call($exec:expr, $layer:expr)) => {
$crate::event::Event::Call($exec, $layer).emit(); $crate::event::Event::Call($exec, $layer).emit();
}; };
(Seq($execs:expr, $layer:expr)) => {
$crate::event::Event::Seq($execs, $layer).emit();
};
($event:ident) => { ($event:ident) => {
$crate::event::Event::$event.emit(); $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)] #[derive(Debug, Default)]
pub struct Exec { pub struct Exec {
pub cmd: String, pub cmd: String,
pub args: Vec<String>, pub args: Vec<String>,
pub named: BTreeMap<String, String>, pub named: BTreeMap<String, String>,
pub data: RefCell<Option<Box<dyn Any + Send>>>, pub data: Option<Box<dyn Any + Send>>,
} }
impl Exec { impl Exec {
@ -19,9 +19,6 @@ impl Exec {
Exec { cmd: cwd.to_owned(), named, ..Default::default() } Exec { cmd: cwd.to_owned(), named, ..Default::default() }
} }
#[inline]
pub fn vec(self) -> Vec<Self> { vec![self] }
#[inline] #[inline]
pub fn with(mut self, name: impl ToString, value: impl ToString) -> Self { pub fn with(mut self, name: impl ToString, value: impl ToString) -> Self {
self.named.insert(name.to_string(), value.to_string()); self.named.insert(name.to_string(), value.to_string());
@ -38,13 +35,31 @@ impl Exec {
#[inline] #[inline]
pub fn with_data(mut self, data: impl Any + Send) -> Self { 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 self
} }
#[inline] #[inline]
pub fn take_data<T: 'static>(&self) -> Option<T> { pub fn take_data<T: 'static>(&mut self) -> Option<T> {
self.data.replace(None).and_then(|d| d.downcast::<T>().ok()).map(|d| *d) 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] #[inline]
pub fn emit(self) { 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 { pub fn prepare(url: &Url) -> u64 {