mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-24 16:21:04 +00:00
feat: expand the types supported by the event system (#923)
This commit is contained in:
parent
2975b999bf
commit
09bc9aa371
99 changed files with 605 additions and 502 deletions
|
|
@ -15,9 +15,7 @@ pub struct Control {
|
||||||
|
|
||||||
impl Control {
|
impl Control {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_seq(&self) -> VecDeque<Cmd> {
|
pub fn to_seq(&self) -> VecDeque<Cmd> { self.run.iter().map(|c| c.shallow_clone()).collect() }
|
||||||
self.run.iter().map(|e| e.clone_without_data()).collect()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Control {
|
impl Control {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
use std::fmt;
|
use std::{fmt, mem};
|
||||||
|
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use serde::{de::{self, Visitor}, Deserializer};
|
use serde::{de::{self, Visitor}, Deserializer};
|
||||||
use yazi_shared::event::Cmd;
|
use yazi_shared::event::{Cmd, Data};
|
||||||
|
|
||||||
pub(super) fn run_deserialize<'de, D>(deserializer: D) -> Result<Vec<Cmd>, D::Error>
|
pub(super) fn run_deserialize<'de, D>(deserializer: D) -> Result<Vec<Cmd>, D::Error>
|
||||||
where
|
where
|
||||||
|
|
@ -10,21 +10,28 @@ where
|
||||||
{
|
{
|
||||||
struct RunVisitor;
|
struct RunVisitor;
|
||||||
|
|
||||||
|
#[allow(clippy::explicit_counter_loop)]
|
||||||
fn parse(s: &str) -> Result<Cmd> {
|
fn parse(s: &str) -> Result<Cmd> {
|
||||||
let s = shell_words::split(s)?;
|
let mut args = shell_words::split(s)?;
|
||||||
if s.is_empty() {
|
let mut cmd = Cmd { name: mem::take(&mut args[0]), ..Default::default() };
|
||||||
bail!("`run` cannot be empty");
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut cmd = Cmd { name: s[0].clone(), ..Default::default() };
|
let mut i = 0usize;
|
||||||
for arg in s.into_iter().skip(1) {
|
for arg in args.into_iter().skip(1) {
|
||||||
if arg.starts_with("--") {
|
let Some(arg) = arg.strip_prefix("--") else {
|
||||||
let mut arg = arg.splitn(2, '=');
|
cmd.args.insert(i.to_string(), Data::String(arg));
|
||||||
let key = arg.next().unwrap().trim_start_matches('-');
|
i += 1;
|
||||||
let val = arg.next().unwrap_or("").to_string();
|
continue;
|
||||||
cmd.named.insert(key.to_string(), val);
|
};
|
||||||
|
|
||||||
|
let mut parts = arg.splitn(2, '=');
|
||||||
|
let Some(key) = parts.next().map(|s| s.to_owned()) else {
|
||||||
|
bail!("invalid argument: {arg}");
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(val) = parts.next() {
|
||||||
|
cmd.args.insert(key, Data::String(val.to_owned()));
|
||||||
} else {
|
} else {
|
||||||
cmd.args.push(arg);
|
cmd.args.insert(key, Data::Boolean(true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(cmd)
|
Ok(cmd)
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ pub struct Opt {
|
||||||
|
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(mut c: Cmd) -> Self {
|
fn from(mut c: Cmd) -> Self {
|
||||||
Self { step: c.take_first().and_then(|s| s.parse().ok()).unwrap_or(0) }
|
Self { step: c.take_first_str().and_then(|s| s.parse().ok()).unwrap_or(0) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ pub struct Opt {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(c: Cmd) -> Self { Self { submit: c.named.contains_key("submit") } }
|
fn from(c: Cmd) -> Self { Self { submit: c.get_bool("submit") } }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Completion {
|
impl Completion {
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,10 @@ pub struct Opt {
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(mut c: Cmd) -> Self {
|
fn from(mut c: Cmd) -> Self {
|
||||||
Self {
|
Self {
|
||||||
cache: mem::take(&mut c.args),
|
cache: c.take_any("cache").unwrap_or_default(),
|
||||||
cache_name: c.take_name("cache-name").unwrap_or_default(),
|
cache_name: c.take_str("cache-name").unwrap_or_default(),
|
||||||
word: c.take_name("word").unwrap_or_default(),
|
word: c.take_str("word").unwrap_or_default(),
|
||||||
ticket: c.take_name("ticket").and_then(|v| v.parse().ok()).unwrap_or(0),
|
ticket: c.take_str("ticket").and_then(|v| v.parse().ok()).unwrap_or(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -63,7 +63,7 @@ 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);
|
||||||
}
|
}
|
||||||
let Some(cache) = self.caches.get(&opt.cache_name) else {
|
let Some(cache) = self.caches.get(&opt.cache_name) else {
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,8 @@ pub struct Opt {
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(mut c: Cmd) -> Self {
|
fn from(mut c: Cmd) -> Self {
|
||||||
Self {
|
Self {
|
||||||
word: c.take_first().unwrap_or_default(),
|
word: c.take_first_str().unwrap_or_default(),
|
||||||
ticket: c.take_name("ticket").and_then(|s| s.parse().ok()).unwrap_or(0),
|
ticket: c.take_str("ticket").and_then(|s| s.parse().ok()).unwrap_or(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -57,7 +57,8 @@ impl Completion {
|
||||||
|
|
||||||
if !cache.is_empty() {
|
if !cache.is_empty() {
|
||||||
emit!(Call(
|
emit!(Call(
|
||||||
Cmd::args("show", cache)
|
Cmd::new("show")
|
||||||
|
.with_any("cache", cache)
|
||||||
.with("cache-name", parent)
|
.with("cache-name", parent)
|
||||||
.with("word", child)
|
.with("word", child)
|
||||||
.with("ticket", ticket),
|
.with("ticket", ticket),
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ pub enum FilterCase {
|
||||||
|
|
||||||
impl From<&Cmd> for FilterCase {
|
impl From<&Cmd> for FilterCase {
|
||||||
fn from(c: &Cmd) -> Self {
|
fn from(c: &Cmd) -> Self {
|
||||||
match (c.named.contains_key("smart"), c.named.contains_key("insensitive")) {
|
match (c.get_bool("smart"), c.get_bool("insensitive")) {
|
||||||
(true, _) => Self::Smart,
|
(true, _) => Self::Smart,
|
||||||
(_, false) => Self::Sensitive,
|
(_, false) => Self::Sensitive,
|
||||||
(_, true) => Self::Insensitive,
|
(_, true) => Self::Insensitive,
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ pub struct Opt {
|
||||||
|
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(mut c: Cmd) -> Self {
|
fn from(mut c: Cmd) -> Self {
|
||||||
Self { step: c.take_first().and_then(|s| s.parse().ok()).unwrap_or(0) }
|
Self { step: c.take_first_str().and_then(|s| s.parse().ok()).unwrap_or(0) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl From<isize> for Opt {
|
impl From<isize> for Opt {
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ pub struct Opt {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(c: Cmd) -> Self { Self { under: c.named.contains_key("under") } }
|
fn from(c: Cmd) -> Self { Self { under: c.get_bool("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 } }
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ pub struct Opt {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(c: Cmd) -> Self { Self { submit: c.named.contains_key("submit") } }
|
fn from(c: Cmd) -> Self { Self { submit: c.get_bool("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 } }
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,8 @@ pub struct Opt {
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(mut c: Cmd) -> Self {
|
fn from(mut c: Cmd) -> Self {
|
||||||
Self {
|
Self {
|
||||||
word: c.take_first().unwrap_or_default(),
|
word: c.take_first_str().unwrap_or_default(),
|
||||||
ticket: c.take_name("ticket").and_then(|s| s.parse().ok()).unwrap_or(0),
|
ticket: c.take_str("ticket").and_then(|s| s.parse().ok()).unwrap_or(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,7 @@ pub struct Opt {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(c: Cmd) -> Self {
|
fn from(c: Cmd) -> Self { Self { cut: c.get_bool("cut"), insert: c.get_bool("insert") } }
|
||||||
Self { cut: c.named.contains_key("cut"), insert: c.named.contains_key("insert") }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Input {
|
impl Input {
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ pub struct Opt {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(c: Cmd) -> Self { Self { end_of_word: c.named.contains_key("end-of-word") } }
|
fn from(c: Cmd) -> Self { Self { end_of_word: c.get_bool("end-of-word") } }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Input {
|
impl Input {
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ pub struct Opt {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(c: Cmd) -> Self { Self { append: c.named.contains_key("append") } }
|
fn from(c: Cmd) -> Self { Self { append: c.get_bool("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 } }
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ pub struct Opt {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(mut c: Cmd) -> Self { Self { kind: c.take_first().unwrap_or_default() } }
|
fn from(mut c: Cmd) -> Self { Self { kind: c.take_first_str().unwrap_or_default() } }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Input {
|
impl Input {
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@ pub struct Opt {
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(mut c: Cmd) -> Self {
|
fn from(mut c: Cmd) -> Self {
|
||||||
Self {
|
Self {
|
||||||
step: c.take_first().and_then(|s| s.parse().ok()).unwrap_or(0),
|
step: c.take_first_str().and_then(|s| s.parse().ok()).unwrap_or(0),
|
||||||
in_operating: c.named.contains_key("in-operating"),
|
in_operating: c.get_bool("in-operating"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ pub struct Opt {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(c: Cmd) -> Self { Self { before: c.named.contains_key("before") } }
|
fn from(c: Cmd) -> Self { Self { before: c.get_bool("before") } }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Input {
|
impl Input {
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,24 @@
|
||||||
use yazi_proxy::options::InputOpt;
|
use tokio::sync::mpsc;
|
||||||
use yazi_shared::render;
|
use yazi_config::popup::InputCfg;
|
||||||
|
use yazi_shared::{event::Cmd, render, InputError};
|
||||||
|
|
||||||
use crate::input::Input;
|
use crate::input::Input;
|
||||||
|
|
||||||
|
pub struct Opt {
|
||||||
|
cfg: InputCfg,
|
||||||
|
tx: mpsc::UnboundedSender<Result<String, InputError>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<Cmd> for Opt {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> {
|
||||||
|
Ok(Self { cfg: c.take_any("cfg").ok_or(())?, tx: c.take_any("tx").ok_or(())? })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Input {
|
impl Input {
|
||||||
pub fn show(&mut self, opt: impl TryInto<InputOpt>) {
|
pub fn show(&mut self, opt: impl TryInto<Opt>) {
|
||||||
let Ok(opt) = opt.try_into() else { return };
|
let Ok(opt) = opt.try_into() else { return };
|
||||||
|
|
||||||
self.close(false);
|
self.close(false);
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ pub struct Opt {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(c: Cmd) -> Self { Self { force: c.named.contains_key("force") } }
|
fn from(c: Cmd) -> Self { Self { force: c.get_bool("force") } }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Manager {
|
impl Manager {
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ pub struct Opt {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(mut c: Cmd) -> Self { Self { url: c.take_first().map(Url::from) } }
|
fn from(mut c: Cmd) -> Self { Self { url: c.take_first_str().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 } }
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,7 @@ pub struct Opt {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(c: Cmd) -> Self {
|
fn from(c: Cmd) -> Self { Self { relative: c.get_bool("relative"), force: c.get_bool("force") } }
|
||||||
Self { relative: c.named.contains_key("relative"), force: c.named.contains_key("force") }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Manager {
|
impl Manager {
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,7 @@ pub struct Opt {
|
||||||
|
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(c: Cmd) -> Self {
|
fn from(c: Cmd) -> Self {
|
||||||
Self {
|
Self { interactive: c.get_bool("interactive"), hovered: c.get_bool("hovered") }
|
||||||
interactive: c.named.contains_key("interactive"),
|
|
||||||
hovered: c.named.contains_key("hovered"),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,7 @@ pub struct Opt {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(c: Cmd) -> Self {
|
fn from(c: Cmd) -> Self { Self { force: c.get_bool("force"), follow: c.get_bool("follow") } }
|
||||||
Self { force: c.named.contains_key("force"), follow: c.named.contains_key("follow") }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Manager {
|
impl Manager {
|
||||||
|
|
|
||||||
|
|
@ -13,10 +13,10 @@ pub struct Opt {
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(mut c: Cmd) -> Self {
|
fn from(mut c: Cmd) -> Self {
|
||||||
Self {
|
Self {
|
||||||
skip: c.take_first().and_then(|s| s.parse().ok()),
|
skip: c.take_first_str().and_then(|s| s.parse().ok()),
|
||||||
force: c.named.contains_key("force"),
|
force: c.get_bool("force"),
|
||||||
only_if: c.take_name("only-if").map(Url::from),
|
only_if: c.take_str("only-if").map(Url::from),
|
||||||
upper_bound: c.named.contains_key("upper-bound"),
|
upper_bound: c.get_bool("upper-bound"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ impl From<()> for Opt {
|
||||||
fn from(_: ()) -> Self { Self::default() }
|
fn from(_: ()) -> Self { Self::default() }
|
||||||
}
|
}
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(c: Cmd) -> Self { Self { no_cwd_file: c.named.contains_key("no-cwd-file") } }
|
fn from(c: Cmd) -> Self { Self { no_cwd_file: c.get_bool("no-cwd-file") } }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Manager {
|
impl Manager {
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,9 @@ pub struct Opt {
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(mut c: Cmd) -> Self {
|
fn from(mut c: Cmd) -> Self {
|
||||||
Self {
|
Self {
|
||||||
force: c.named.contains_key("force"),
|
force: c.get_bool("force"),
|
||||||
permanently: c.named.contains_key("permanently"),
|
permanently: c.get_bool("permanently"),
|
||||||
targets: c.take_data().unwrap_or_default(),
|
targets: c.take_any("targets").unwrap_or_default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,9 @@ pub struct Opt {
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(mut c: Cmd) -> Self {
|
fn from(mut c: Cmd) -> Self {
|
||||||
Self {
|
Self {
|
||||||
force: c.named.contains_key("force"),
|
force: c.get_bool("force"),
|
||||||
empty: c.take_name("empty").unwrap_or_default(),
|
empty: c.take_str("empty").unwrap_or_default(),
|
||||||
cursor: c.take_name("cursor").unwrap_or_default(),
|
cursor: c.take_str("cursor").unwrap_or_default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ pub struct Opt {
|
||||||
|
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(mut c: Cmd) -> Self {
|
fn from(mut c: Cmd) -> Self {
|
||||||
Self { units: c.take_first().and_then(|s| s.parse().ok()).unwrap_or(0) }
|
Self { units: c.take_first_str().and_then(|s| s.parse().ok()).unwrap_or(0) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ pub struct Opt {
|
||||||
|
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(mut c: Cmd) -> Self {
|
fn from(mut c: Cmd) -> Self {
|
||||||
Self { idx: c.take_first().and_then(|i| i.parse().ok()).unwrap_or(0) }
|
Self { idx: c.take_first_str().and_then(|i| i.parse().ok()).unwrap_or(0) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,11 +13,11 @@ pub struct Opt {
|
||||||
|
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(mut c: Cmd) -> Self {
|
fn from(mut c: Cmd) -> Self {
|
||||||
if c.named.contains_key("current") {
|
if c.get_bool("current") {
|
||||||
Self { url: Default::default(), current: true }
|
Self { url: Default::default(), current: true }
|
||||||
} else {
|
} else {
|
||||||
Self {
|
Self {
|
||||||
url: c.take_first().map_or_else(|| Url::from(&BOOT.cwd), Url::from),
|
url: c.take_first_str().map_or_else(|| Url::from(&BOOT.cwd), Url::from),
|
||||||
current: false,
|
current: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ pub struct Opt {
|
||||||
|
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(mut c: Cmd) -> Self {
|
fn from(mut c: Cmd) -> Self {
|
||||||
Self { step: c.take_first().and_then(|s| s.parse().ok()).unwrap_or(0) }
|
Self { step: c.take_first_str().and_then(|s| s.parse().ok()).unwrap_or(0) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,8 @@ pub struct Opt {
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(mut c: Cmd) -> Self {
|
fn from(mut c: Cmd) -> Self {
|
||||||
Self {
|
Self {
|
||||||
step: c.take_first().and_then(|s| s.parse().ok()).unwrap_or(0),
|
step: c.take_first_str().and_then(|s| s.parse().ok()).unwrap_or(0),
|
||||||
relative: c.named.contains_key("relative"),
|
relative: c.get_bool("relative"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,9 @@ pub struct Opt {
|
||||||
impl TryFrom<Cmd> for Opt {
|
impl TryFrom<Cmd> for Opt {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> { Ok(Self { op: c.take_data().ok_or(())? }) }
|
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> {
|
||||||
|
Ok(Self { op: c.take_any("op").ok_or(())? })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Manager {
|
impl Manager {
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,18 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use yazi_dds::ValueSendable;
|
|
||||||
use yazi_shared::{event::Cmd, fs::Url, render};
|
use yazi_shared::{event::Cmd, fs::Url, render};
|
||||||
|
|
||||||
use crate::{manager::{Manager, LINKED}, tasks::Tasks};
|
use crate::{manager::{Manager, LINKED}, tasks::Tasks};
|
||||||
|
|
||||||
pub struct Opt {
|
pub struct Opt {
|
||||||
data: ValueSendable,
|
updates: HashMap<String, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<Cmd> for Opt {
|
impl TryFrom<Cmd> for Opt {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> {
|
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> {
|
||||||
Ok(Self { data: c.take_data().ok_or(())? })
|
Ok(Self { updates: c.take_data("updates").ok_or(())?.into_table_string() })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -25,8 +24,7 @@ impl Manager {
|
||||||
|
|
||||||
let linked = LINKED.read();
|
let linked = LINKED.read();
|
||||||
let updates = opt
|
let updates = opt
|
||||||
.data
|
.updates
|
||||||
.into_table_string()
|
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(url, mime)| (Url::from(url), mime))
|
.map(|(url, mime)| (Url::from(url), mime))
|
||||||
.filter(|(url, mime)| self.mimetype.get(url) != Some(mime))
|
.filter(|(url, mime)| self.mimetype.get(url) != Some(mime))
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@ pub struct Opt {
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(mut c: Cmd) -> Self {
|
fn from(mut c: Cmd) -> Self {
|
||||||
Self {
|
Self {
|
||||||
page: c.take_first().and_then(|s| s.parse().ok()),
|
page: c.take_first_str().and_then(|s| s.parse().ok()),
|
||||||
only_if: c.take_name("only-if").map(Url::from),
|
only_if: c.take_str("only-if").map(Url::from),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ pub struct Opt {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(c: Cmd) -> Self { Self { cut: c.named.contains_key("cut") } }
|
fn from(c: Cmd) -> Self { Self { cut: c.get_bool("cut") } }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Manager {
|
impl Manager {
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ impl TryFrom<Cmd> for Opt {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> {
|
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> {
|
||||||
let interval = c.take_first().and_then(|s| s.parse::<f64>().ok()).ok_or(())?;
|
let interval = c.take_first_str().and_then(|s| s.parse::<f64>().ok()).ok_or(())?;
|
||||||
if interval < 0.0 {
|
if interval < 0.0 {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ pub struct Opt {
|
||||||
|
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(mut c: Cmd) -> Self {
|
fn from(mut c: Cmd) -> Self {
|
||||||
Self { step: c.take_first().and_then(|s| s.parse().ok()).unwrap_or(0) }
|
Self { step: c.take_first_str().and_then(|s| s.parse().ok()).unwrap_or(0) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ pub struct Opt {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(c: Cmd) -> Self { Self { submit: c.named.contains_key("submit") } }
|
fn from(c: Cmd) -> Self { Self { submit: c.get_bool("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 } }
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,24 @@
|
||||||
use yazi_proxy::options::SelectOpt;
|
use tokio::sync::oneshot;
|
||||||
use yazi_shared::render;
|
use yazi_config::popup::SelectCfg;
|
||||||
|
use yazi_shared::{event::Cmd, render};
|
||||||
|
|
||||||
use crate::select::Select;
|
use crate::select::Select;
|
||||||
|
|
||||||
|
pub struct Opt {
|
||||||
|
cfg: SelectCfg,
|
||||||
|
tx: oneshot::Sender<anyhow::Result<usize>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<Cmd> for Opt {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> {
|
||||||
|
Ok(Self { cfg: c.take_any("cfg").ok_or(())?, tx: c.take_any("tx").ok_or(())? })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Select {
|
impl Select {
|
||||||
pub fn show(&mut self, opt: impl TryInto<SelectOpt>) {
|
pub fn show(&mut self, opt: impl TryInto<Opt>) {
|
||||||
let Ok(opt) = opt.try_into() else {
|
let Ok(opt) = opt.try_into() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ pub struct Opt {
|
||||||
|
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(mut c: Cmd) -> Self {
|
fn from(mut c: Cmd) -> Self {
|
||||||
Self { step: c.take_first().and_then(|s| s.parse().ok()).unwrap_or_default() }
|
Self { step: c.take_first_str().and_then(|s| s.parse().ok()).unwrap_or_default() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,12 @@ pub struct Opt {
|
||||||
|
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(mut c: Cmd) -> Self {
|
fn from(mut c: Cmd) -> Self {
|
||||||
let mut target = Url::from(c.take_first().unwrap_or_default());
|
let mut target = Url::from(c.take_first_str().unwrap_or_default());
|
||||||
if target.is_regular() {
|
if target.is_regular() {
|
||||||
target.set_path(expand_path(&target))
|
target.set_path(expand_path(&target))
|
||||||
}
|
}
|
||||||
|
|
||||||
Self { target, interactive: c.named.contains_key("interactive") }
|
Self { target, interactive: c.get_bool("interactive") }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl From<Url> for Opt {
|
impl From<Url> for Opt {
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ pub struct Opt {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(mut c: Cmd) -> Self { Self { type_: c.take_first().unwrap_or_default() } }
|
fn from(mut c: Cmd) -> Self { Self { type_: c.take_first_str().unwrap_or_default() } }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Tab {
|
impl Tab {
|
||||||
|
|
|
||||||
|
|
@ -16,14 +16,16 @@ bitflags! {
|
||||||
|
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(c: Cmd) -> Self {
|
fn from(c: Cmd) -> Self {
|
||||||
c.named.iter().fold(Opt::empty(), |acc, (k, _)| match k.as_str() {
|
c.args.iter().fold(Opt::empty(), |acc, (k, v)| {
|
||||||
"all" => Self::all(),
|
match (k.as_str(), v.as_bool().unwrap_or(false)) {
|
||||||
"find" => acc | Self::FIND,
|
("all", true) => Self::all(),
|
||||||
"visual" => acc | Self::VISUAL,
|
("find", true) => acc | Self::FIND,
|
||||||
"select" => acc | Self::SELECT,
|
("visual", true) => acc | Self::VISUAL,
|
||||||
"filter" => acc | Self::FILTER,
|
("select", true) => acc | Self::SELECT,
|
||||||
"search" => acc | Self::SEARCH,
|
("filter", true) => acc | Self::FILTER,
|
||||||
_ => acc,
|
("search", true) => acc | Self::SEARCH,
|
||||||
|
_ => acc,
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,9 @@ pub struct Opt {
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(mut c: Cmd) -> Self {
|
fn from(mut c: Cmd) -> Self {
|
||||||
Self {
|
Self {
|
||||||
query: c.take_first().unwrap_or_default(),
|
query: c.take_first_str().unwrap_or_default(),
|
||||||
case: FilterCase::from(&c),
|
case: FilterCase::from(&c),
|
||||||
done: c.named.contains_key("done"),
|
done: c.get_bool("done"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,11 +16,7 @@ pub struct Opt {
|
||||||
|
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(mut c: Cmd) -> Self {
|
fn from(mut c: Cmd) -> Self {
|
||||||
Self {
|
Self { query: c.take_first_str(), prev: c.get_bool("previous"), case: FilterCase::from(&c) }
|
||||||
query: c.take_first(),
|
|
||||||
prev: c.named.contains_key("previous"),
|
|
||||||
case: FilterCase::from(&c),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -29,7 +25,7 @@ pub struct ArrowOpt {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Cmd> for ArrowOpt {
|
impl From<Cmd> for ArrowOpt {
|
||||||
fn from(c: Cmd) -> Self { Self { prev: c.named.contains_key("previous") } }
|
fn from(c: Cmd) -> Self { Self { prev: c.get_bool("previous") } }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Tab {
|
impl Tab {
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ use yazi_shared::event::Cmd;
|
||||||
use crate::tab::Tab;
|
use crate::tab::Tab;
|
||||||
|
|
||||||
impl Tab {
|
impl Tab {
|
||||||
pub fn hidden(&mut self, c: Cmd) {
|
pub fn hidden(&mut self, mut c: Cmd) {
|
||||||
self.conf.show_hidden = match c.args.first().map(|s| s.as_str()) {
|
self.conf.show_hidden = match c.take_first_str().as_deref() {
|
||||||
Some("show") => true,
|
Some("show") => true,
|
||||||
Some("hide") => false,
|
Some("hide") => false,
|
||||||
_ => !self.conf.show_hidden,
|
_ => !self.conf.show_hidden,
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,9 @@ pub enum OptType {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(c: Cmd) -> Self {
|
fn from(mut c: Cmd) -> Self {
|
||||||
Self {
|
Self {
|
||||||
type_: match c.args.first().map(|s| s.as_str()) {
|
type_: match c.take_first_str().as_deref() {
|
||||||
Some("fzf") => OptType::Fzf,
|
Some("fzf") => OptType::Fzf,
|
||||||
Some("zoxide") => OptType::Zoxide,
|
Some("zoxide") => OptType::Zoxide,
|
||||||
_ => OptType::None,
|
_ => OptType::None,
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use crate::tab::Tab;
|
||||||
impl Tab {
|
impl Tab {
|
||||||
pub fn linemode(&mut self, mut c: Cmd) {
|
pub fn linemode(&mut self, mut c: Cmd) {
|
||||||
render!(self.conf.patch(|new| {
|
render!(self.conf.patch(|new| {
|
||||||
let Some(mode) = c.take_first() else {
|
let Some(mode) = c.take_first_str() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if !mode.is_empty() && mode.len() <= 20 {
|
if !mode.is_empty() && mode.len() <= 20 {
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ impl TryFrom<Cmd> for Opt {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> {
|
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> {
|
||||||
Ok(Self { lock: c.take_data().ok_or(())? })
|
Ok(Self { lock: c.take_any("lock").ok_or(())? })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ pub struct Opt {
|
||||||
|
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(mut c: Cmd) -> Self {
|
fn from(mut c: Cmd) -> Self {
|
||||||
let mut target = Url::from(c.take_first().unwrap_or_default());
|
let mut target = Url::from(c.take_first_str().unwrap_or_default());
|
||||||
if target.is_regular() {
|
if target.is_regular() {
|
||||||
target.set_path(expand_path(&target))
|
target.set_path(expand_path(&target))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ pub struct Opt {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(mut c: Cmd) -> Self { Self { type_: c.take_first().unwrap_or_default().into() } }
|
fn from(mut c: Cmd) -> Self { Self { type_: c.take_first_str().unwrap_or_default().into() } }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Tab {
|
impl Tab {
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,8 @@ pub struct Opt<'a> {
|
||||||
impl<'a> From<Cmd> for Opt<'a> {
|
impl<'a> From<Cmd> for Opt<'a> {
|
||||||
fn from(mut c: Cmd) -> Self {
|
fn from(mut c: Cmd) -> Self {
|
||||||
Self {
|
Self {
|
||||||
url: c.take_name("url").map(|s| Cow::Owned(Url::from(s))),
|
url: c.take_str("url").map(|s| Cow::Owned(Url::from(s))),
|
||||||
state: match c.named.get("state").map(|s| s.as_str()) {
|
state: match c.take_str("state").as_deref() {
|
||||||
Some("true") => Some(true),
|
Some("true") => Some(true),
|
||||||
Some("false") => Some(false),
|
Some("false") => Some(false),
|
||||||
_ => None,
|
_ => None,
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,9 @@ pub struct Opt {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(c: Cmd) -> Self {
|
fn from(mut c: Cmd) -> Self {
|
||||||
Self {
|
Self {
|
||||||
state: match c.named.get("state").map(|s| s.as_str()) {
|
state: match c.take_str("state").as_deref() {
|
||||||
Some("true") => Some(true),
|
Some("true") => Some(true),
|
||||||
Some("false") => Some(false),
|
Some("false") => Some(false),
|
||||||
_ => None,
|
_ => None,
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,10 @@ pub struct Opt {
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(mut c: Cmd) -> Self {
|
fn from(mut c: Cmd) -> Self {
|
||||||
Self {
|
Self {
|
||||||
run: c.take_first().unwrap_or_default(),
|
run: c.take_first_str().unwrap_or_default(),
|
||||||
block: c.named.contains_key("block"),
|
block: c.get_bool("block"),
|
||||||
orphan: c.named.contains_key("orphan"),
|
orphan: c.get_bool("orphan"),
|
||||||
confirm: c.named.contains_key("confirm"),
|
confirm: c.get_bool("confirm"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,13 @@ use yazi_shared::event::Cmd;
|
||||||
use crate::{tab::Tab, tasks::Tasks};
|
use crate::{tab::Tab, tasks::Tasks};
|
||||||
|
|
||||||
impl Tab {
|
impl Tab {
|
||||||
pub fn sort(&mut self, c: Cmd, tasks: &Tasks) {
|
pub fn sort(&mut self, mut c: Cmd, tasks: &Tasks) {
|
||||||
if let Some(by) = c.args.first() {
|
if let Some(by) = c.take_first_str() {
|
||||||
self.conf.sort_by = SortBy::from_str(by).unwrap_or_default();
|
self.conf.sort_by = SortBy::from_str(&by).unwrap_or_default();
|
||||||
}
|
}
|
||||||
self.conf.sort_sensitive = c.named.contains_key("sensitive");
|
self.conf.sort_sensitive = c.get_bool("sensitive");
|
||||||
self.conf.sort_reverse = c.named.contains_key("reverse");
|
self.conf.sort_reverse = c.get_bool("reverse");
|
||||||
self.conf.sort_dir_first = c.named.contains_key("dir-first");
|
self.conf.sort_dir_first = c.get_bool("dir-first");
|
||||||
|
|
||||||
self.apply_files_attrs();
|
self.apply_files_attrs();
|
||||||
ManagerProxy::update_paged();
|
ManagerProxy::update_paged();
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ pub struct Opt {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(c: Cmd) -> Self { Self { unset: c.named.contains_key("unset") } }
|
fn from(c: Cmd) -> Self { Self { unset: c.get_bool("unset") } }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Tab {
|
impl Tab {
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ pub struct Opt {
|
||||||
|
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(mut c: Cmd) -> Self {
|
fn from(mut c: Cmd) -> Self {
|
||||||
Self { step: c.take_first().and_then(|s| s.parse().ok()).unwrap_or(0) }
|
Self { step: c.take_first_str().and_then(|s| s.parse().ok()).unwrap_or(0) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
use yazi_dds::ValueSendable;
|
use yazi_shared::event::Data;
|
||||||
|
|
||||||
use super::Tasks;
|
use super::Tasks;
|
||||||
|
|
||||||
impl Tasks {
|
impl Tasks {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn plugin_micro(&self, name: String, args: Vec<ValueSendable>) {
|
pub fn plugin_micro(&self, name: String, args: Vec<Data>) {
|
||||||
self.scheduler.plugin_micro(name, args);
|
self.scheduler.plugin_micro(name, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn plugin_macro(&self, name: String, args: Vec<ValueSendable>) {
|
pub fn plugin_macro(&self, name: String, args: Vec<Data>) {
|
||||||
self.scheduler.plugin_macro(name, args);
|
self.scheduler.plugin_macro(name, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ impl Tasks {
|
||||||
let new = TasksProgress::from(&*ongoing.lock());
|
let new = TasksProgress::from(&*ongoing.lock());
|
||||||
if last != new {
|
if last != new {
|
||||||
last = new;
|
last = new;
|
||||||
emit!(Call(Cmd::new("update_progress").with_data(new), Layer::App));
|
emit!(Call(Cmd::new("update_progress").with_any("progress", new), Layer::App));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@ impl TryFrom<Cmd> for Opt {
|
||||||
|
|
||||||
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> {
|
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
tx: c.take_data().ok_or(())?,
|
tx: c.take_any("tx").ok_or(())?,
|
||||||
idx: c.take_first().and_then(|s| s.parse().ok()).ok_or(())?,
|
idx: c.take_first_str().and_then(|s| s.parse().ok()).ok_or(())?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,9 @@ impl TryFrom<Cmd> for Opt {
|
||||||
|
|
||||||
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> {
|
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
cands: c.take_data().unwrap_or_default(),
|
cands: c.take_any("candidates").unwrap_or_default(),
|
||||||
layer: Layer::from_str(&c.take_name("layer").unwrap_or_default())?,
|
layer: Layer::from_str(&c.take_str("layer").unwrap_or_default())?,
|
||||||
silent: c.named.contains_key("silent"),
|
silent: c.get_bool("silent"),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,25 @@
|
||||||
use mlua::{IntoLua, Lua, Value};
|
use mlua::{IntoLua, Lua, Value};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
use yazi_shared::event::Data;
|
||||||
|
|
||||||
use super::Body;
|
use super::Body;
|
||||||
use crate::ValueSendable;
|
use crate::Sendable;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct BodyCustom {
|
pub struct BodyCustom {
|
||||||
pub kind: String,
|
pub kind: String,
|
||||||
pub value: ValueSendable,
|
pub data: Data,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BodyCustom {
|
impl BodyCustom {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_str(kind: &str, value: &str) -> anyhow::Result<Body<'static>> {
|
pub fn from_str(kind: &str, data: &str) -> anyhow::Result<Body<'static>> {
|
||||||
Ok(Self { kind: kind.to_owned(), value: serde_json::from_str(value)? }.into())
|
Ok(Self { kind: kind.to_owned(), data: serde_json::from_str(data)? }.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_lua(kind: &str, value: Value) -> mlua::Result<Body<'static>> {
|
pub fn from_lua(kind: &str, data: Value) -> mlua::Result<Body<'static>> {
|
||||||
Ok(Self { kind: kind.to_owned(), value: value.try_into()? }.into())
|
Ok(Self { kind: kind.to_owned(), data: Sendable::value_to_data(data)? }.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -27,11 +28,11 @@ impl From<BodyCustom> for Body<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoLua<'_> for BodyCustom {
|
impl IntoLua<'_> for BodyCustom {
|
||||||
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> { self.value.into_lua(lua) }
|
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> { Sendable::data_to_value(lua, self.data) }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for BodyCustom {
|
impl Serialize for BodyCustom {
|
||||||
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||||
serde::Serialize::serialize(&self.value, serializer)
|
serde::Serialize::serialize(&self.data, serializer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ impl Payload<'static> {
|
||||||
|
|
||||||
pub(super) fn emit(self) {
|
pub(super) fn emit(self) {
|
||||||
self.try_flush();
|
self.try_flush();
|
||||||
emit!(Call(Cmd::new("accept_payload").with_data(self), Layer::App));
|
emit!(Call(Cmd::new("accept_payload").with_any("payload", self), Layer::App));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,129 +1,122 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use mlua::{ExternalError, IntoLua, Lua, Value, Variadic};
|
use mlua::{ExternalError, Lua, Table, Value, Variadic};
|
||||||
use serde::{Deserialize, Serialize};
|
use yazi_shared::{event::{Data, DataKey}, OrderedFloat};
|
||||||
use yazi_shared::OrderedFloat;
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
pub struct Sendable;
|
||||||
#[serde(untagged)]
|
|
||||||
pub enum ValueSendable {
|
|
||||||
Nil,
|
|
||||||
Boolean(bool),
|
|
||||||
Integer(i64),
|
|
||||||
Number(f64),
|
|
||||||
String(String),
|
|
||||||
Table(HashMap<ValueSendableKey, ValueSendable>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ValueSendable {
|
impl Sendable {
|
||||||
pub fn try_from_variadic(values: Variadic<Value>) -> mlua::Result<Vec<Self>> {
|
pub fn value_to_data(value: Value) -> mlua::Result<Data> {
|
||||||
|
Ok(match value {
|
||||||
|
Value::Nil => Data::Nil,
|
||||||
|
Value::Boolean(b) => Data::Boolean(b),
|
||||||
|
Value::LightUserData(_) => Err("light userdata is not supported".into_lua_err())?,
|
||||||
|
Value::Integer(n) => Data::Integer(n),
|
||||||
|
Value::Number(n) => Data::Number(n),
|
||||||
|
Value::String(s) => Data::String(s.to_str()?.to_owned()),
|
||||||
|
Value::Table(t) => {
|
||||||
|
let mut map = HashMap::with_capacity(t.raw_len());
|
||||||
|
for result in t.pairs::<Value, Value>() {
|
||||||
|
let (k, v) = result?;
|
||||||
|
map.insert(Self::value_to_key(k)?, Self::value_to_data(v)?);
|
||||||
|
}
|
||||||
|
Data::Table(map)
|
||||||
|
}
|
||||||
|
Value::Function(_) => Err("function is not supported".into_lua_err())?,
|
||||||
|
Value::Thread(_) => Err("thread is not supported".into_lua_err())?,
|
||||||
|
Value::UserData(ud) => {
|
||||||
|
if let Ok(t) = ud.take::<yazi_shared::fs::Url>() {
|
||||||
|
Data::Url(t)
|
||||||
|
} else if let Ok(t) = ud.take::<super::body::BodyYankIter>() {
|
||||||
|
Data::Any(Box::new(t))
|
||||||
|
} else {
|
||||||
|
Err("unsupported userdata included".into_lua_err())?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Value::Error(_) => Err("error is not supported".into_lua_err())?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn data_to_value(lua: &Lua, data: Data) -> mlua::Result<Value> {
|
||||||
|
Ok(match data {
|
||||||
|
Data::Nil => Value::Nil,
|
||||||
|
Data::Boolean(v) => Value::Boolean(v),
|
||||||
|
Data::Integer(v) => Value::Integer(v),
|
||||||
|
Data::Number(v) => Value::Number(v),
|
||||||
|
Data::String(v) => Value::String(lua.create_string(v)?),
|
||||||
|
Data::Table(t) => {
|
||||||
|
let seq_len = t.keys().filter(|&k| !k.is_numeric()).count();
|
||||||
|
let table = lua.create_table_with_capacity(seq_len, t.len() - seq_len)?;
|
||||||
|
for (k, v) in t {
|
||||||
|
table.raw_set(Self::key_to_value(lua, k)?, Self::data_to_value(lua, v)?)?;
|
||||||
|
}
|
||||||
|
Value::Table(table)
|
||||||
|
}
|
||||||
|
Data::Url(v) => Value::UserData(lua.create_any_userdata(v)?),
|
||||||
|
Data::Any(v) => {
|
||||||
|
if let Ok(t) = v.downcast::<super::body::BodyYankIter>() {
|
||||||
|
Value::UserData(lua.create_userdata(*t)?)
|
||||||
|
} else {
|
||||||
|
Err("unsupported userdata included".into_lua_err())?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn vec_to_table(lua: &Lua, data: Vec<Data>) -> mlua::Result<Table> {
|
||||||
|
let mut vec = Vec::with_capacity(data.len());
|
||||||
|
for v in data.into_iter() {
|
||||||
|
vec.push(Self::data_to_value(lua, v)?);
|
||||||
|
}
|
||||||
|
lua.create_sequence_from(vec)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn vec_to_variadic(lua: &Lua, data: Vec<Data>) -> mlua::Result<Variadic<Value>> {
|
||||||
|
let mut vec = Vec::with_capacity(data.len());
|
||||||
|
for v in data {
|
||||||
|
vec.push(Self::data_to_value(lua, v)?);
|
||||||
|
}
|
||||||
|
Ok(Variadic::from_iter(vec))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn variadic_to_vec(values: Variadic<Value>) -> mlua::Result<Vec<Data>> {
|
||||||
let mut vec = Vec::with_capacity(values.len());
|
let mut vec = Vec::with_capacity(values.len());
|
||||||
for value in values {
|
for value in values {
|
||||||
vec.push(Self::try_from(value)?);
|
vec.push(Self::value_to_data(value)?);
|
||||||
}
|
}
|
||||||
Ok(vec)
|
Ok(vec)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_table_string(self) -> HashMap<String, String> {
|
fn value_to_key(value: Value) -> mlua::Result<DataKey> {
|
||||||
let Self::Table(table) = self else {
|
|
||||||
return Default::default();
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut map = HashMap::with_capacity(table.len());
|
|
||||||
for pair in table {
|
|
||||||
if let (ValueSendableKey::String(k), Self::String(v)) = pair {
|
|
||||||
map.insert(k, v);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
map
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> TryFrom<Value<'a>> for ValueSendable {
|
|
||||||
type Error = mlua::Error;
|
|
||||||
|
|
||||||
fn try_from(value: Value) -> Result<Self, Self::Error> {
|
|
||||||
Ok(match value {
|
Ok(match value {
|
||||||
Value::Nil => Self::Nil,
|
Value::Nil => DataKey::Nil,
|
||||||
Value::Boolean(b) => Self::Boolean(b),
|
Value::Boolean(v) => DataKey::Boolean(v),
|
||||||
Value::LightUserData(_) => Err("light userdata is not supported".into_lua_err())?,
|
Value::LightUserData(_) => Err("light userdata is not supported".into_lua_err())?,
|
||||||
Value::Integer(n) => Self::Integer(n),
|
Value::Integer(v) => DataKey::Integer(v),
|
||||||
Value::Number(n) => Self::Number(n),
|
Value::Number(v) => DataKey::Number(OrderedFloat::new(v)),
|
||||||
Value::String(s) => Self::String(s.to_str()?.to_owned()),
|
Value::String(v) => DataKey::String(v.to_str()?.to_owned()),
|
||||||
Value::Table(t) => {
|
Value::Table(_) => Err("table is not supported".into_lua_err())?,
|
||||||
let mut map = HashMap::with_capacity(t.len().map(|l| l as usize)?);
|
|
||||||
for result in t.pairs::<Value, Value>() {
|
|
||||||
let (k, v) = result?;
|
|
||||||
map.insert(Self::try_from(k)?.try_into()?, v.try_into()?);
|
|
||||||
}
|
|
||||||
Self::Table(map)
|
|
||||||
}
|
|
||||||
Value::Function(_) => Err("function is not supported".into_lua_err())?,
|
Value::Function(_) => Err("function is not supported".into_lua_err())?,
|
||||||
Value::Thread(_) => Err("thread is not supported".into_lua_err())?,
|
Value::Thread(_) => Err("thread is not supported".into_lua_err())?,
|
||||||
Value::UserData(_) => Err("userdata is not supported".into_lua_err())?,
|
Value::UserData(ud) => {
|
||||||
|
if let Ok(t) = ud.take::<yazi_shared::fs::Url>() {
|
||||||
|
DataKey::Url(t)
|
||||||
|
} else {
|
||||||
|
Err("unsupported userdata included".into_lua_err())?
|
||||||
|
}
|
||||||
|
}
|
||||||
Value::Error(_) => Err("error is not supported".into_lua_err())?,
|
Value::Error(_) => Err("error is not supported".into_lua_err())?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl IntoLua<'_> for ValueSendable {
|
fn key_to_value(lua: &Lua, key: DataKey) -> mlua::Result<Value> {
|
||||||
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {
|
Ok(match key {
|
||||||
match self {
|
DataKey::Nil => Value::Nil,
|
||||||
Self::Nil => Ok(Value::Nil),
|
DataKey::Boolean(k) => Value::Boolean(k),
|
||||||
Self::Boolean(v) => Ok(Value::Boolean(v)),
|
DataKey::Integer(k) => Value::Integer(k),
|
||||||
Self::Integer(v) => Ok(Value::Integer(v)),
|
DataKey::Number(k) => Value::Number(k.get()),
|
||||||
Self::Number(v) => Ok(Value::Number(v)),
|
DataKey::String(k) => Value::String(lua.create_string(k)?),
|
||||||
Self::String(v) => Ok(Value::String(lua.create_string(v)?)),
|
DataKey::Url(k) => Value::UserData(lua.create_any_userdata(k)?),
|
||||||
Self::Table(v) => {
|
|
||||||
let seq_len = v.keys().filter(|&k| !k.is_numeric()).count();
|
|
||||||
let table = lua.create_table_with_capacity(seq_len, v.len() - seq_len)?;
|
|
||||||
for (k, v) in v {
|
|
||||||
table.raw_set(k, v)?;
|
|
||||||
}
|
|
||||||
Ok(Value::Table(table))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
|
||||||
#[serde(untagged)]
|
|
||||||
pub enum ValueSendableKey {
|
|
||||||
Nil,
|
|
||||||
Boolean(bool),
|
|
||||||
Integer(i64),
|
|
||||||
Number(OrderedFloat),
|
|
||||||
String(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ValueSendableKey {
|
|
||||||
#[inline]
|
|
||||||
fn is_numeric(&self) -> bool { matches!(self, Self::Integer(_) | Self::Number(_)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryInto<ValueSendableKey> for ValueSendable {
|
|
||||||
type Error = mlua::Error;
|
|
||||||
|
|
||||||
fn try_into(self) -> Result<ValueSendableKey, Self::Error> {
|
|
||||||
Ok(match self {
|
|
||||||
Self::Nil => ValueSendableKey::Nil,
|
|
||||||
Self::Boolean(v) => ValueSendableKey::Boolean(v),
|
|
||||||
Self::Integer(v) => ValueSendableKey::Integer(v),
|
|
||||||
Self::Number(v) => ValueSendableKey::Number(OrderedFloat::new(v)),
|
|
||||||
Self::String(v) => ValueSendableKey::String(v),
|
|
||||||
Self::Table(_) => Err("table is not supported".into_lua_err())?,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoLua<'_> for ValueSendableKey {
|
|
||||||
fn into_lua(self, lua: &Lua) -> mlua::Result<Value> {
|
|
||||||
match self {
|
|
||||||
Self::Nil => Ok(Value::Nil),
|
|
||||||
Self::Boolean(k) => Ok(Value::Boolean(k)),
|
|
||||||
Self::Integer(k) => Ok(Value::Integer(k)),
|
|
||||||
Self::Number(k) => Ok(Value::Number(k.get())),
|
|
||||||
Self::String(k) => Ok(Value::String(lua.create_string(k)?)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ use crate::{app::App, lives::Lives};
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
pub(crate) fn accept_payload(&mut self, mut cmd: Cmd) {
|
pub(crate) fn accept_payload(&mut self, mut cmd: Cmd) {
|
||||||
let Some(payload) = cmd.take_data::<Payload>() else {
|
let Some(payload) = cmd.take_any::<Payload>("payload") else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,8 @@ use std::fmt::Display;
|
||||||
use mlua::TableExt;
|
use mlua::TableExt;
|
||||||
use scopeguard::defer;
|
use scopeguard::defer;
|
||||||
use tracing::warn;
|
use tracing::warn;
|
||||||
use yazi_plugin::{loader::LOADER, OptData, RtRef, LUA};
|
use yazi_dds::Sendable;
|
||||||
|
use yazi_plugin::{loader::LOADER, RtRef, LUA};
|
||||||
use yazi_shared::{emit, event::Cmd, Layer};
|
use yazi_shared::{emit, event::Cmd, Layer};
|
||||||
|
|
||||||
use crate::{app::App, lives::Lives};
|
use crate::{app::App, lives::Lives};
|
||||||
|
|
@ -16,7 +17,7 @@ impl App {
|
||||||
};
|
};
|
||||||
|
|
||||||
if !opt.sync {
|
if !opt.sync {
|
||||||
return self.cx.tasks.plugin_micro(opt.name, opt.data.args);
|
return self.cx.tasks.plugin_micro(opt.name, opt.args);
|
||||||
}
|
}
|
||||||
|
|
||||||
if LOADER.read().contains_key(&opt.name) {
|
if LOADER.read().contains_key(&opt.name) {
|
||||||
|
|
@ -25,14 +26,15 @@ impl App {
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
if LOADER.ensure(&opt.name).await.is_ok() {
|
if LOADER.ensure(&opt.name).await.is_ok() {
|
||||||
Self::_plugin_do(opt.name, opt.data);
|
Self::_plugin_do(opt);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn _plugin_do(name: String, data: OptData) {
|
pub(crate) fn _plugin_do(opt: yazi_plugin::Opt) {
|
||||||
emit!(Call(Cmd::args("plugin_do", vec![name]).with_data(data), Layer::App));
|
let cmd: Cmd = opt.into();
|
||||||
|
emit!(Call(cmd.with_name("plugin_do"), Layer::App));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn plugin_do(&mut self, opt: impl TryInto<yazi_plugin::Opt, Error = impl Display>) {
|
pub(crate) fn plugin_do(&mut self, opt: impl TryInto<yazi_plugin::Opt, Error = impl Display>) {
|
||||||
|
|
@ -53,10 +55,10 @@ impl App {
|
||||||
};
|
};
|
||||||
|
|
||||||
_ = Lives::scope(&self.cx, |_| {
|
_ = Lives::scope(&self.cx, |_| {
|
||||||
if let Some(cb) = opt.data.cb {
|
if let Some(cb) = opt.cb {
|
||||||
cb(&LUA, plugin)
|
cb(&LUA, plugin)
|
||||||
} else {
|
} else {
|
||||||
plugin.call_method("entry", opt.data.args)
|
plugin.call_method("entry", Sendable::vec_to_table(&LUA, opt.args)?)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ pub struct Opt {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Cmd> for Opt {
|
impl From<Cmd> for Opt {
|
||||||
fn from(mut c: Cmd) -> Self { Self { tx: c.take_data() } }
|
fn from(mut c: Cmd) -> Self { Self { tx: c.take_any("tx") } }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ impl TryFrom<Cmd> for Opt {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> {
|
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> {
|
||||||
Ok(Self { progress: c.take_data().ok_or(())? })
|
Ok(Self { progress: c.take_any("progress").ok_or(())? })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -214,7 +214,7 @@ impl<'a> Executor<'a> {
|
||||||
on!(forward);
|
on!(forward);
|
||||||
|
|
||||||
if cmd.name.as_str() == "complete" {
|
if cmd.name.as_str() == "complete" {
|
||||||
return if cmd.named.contains_key("trigger") {
|
return if cmd.get_bool("trigger") {
|
||||||
self.app.cx.completion.trigger(cmd)
|
self.app.cx.completion.trigger(cmd)
|
||||||
} else {
|
} else {
|
||||||
self.app.cx.input.complete(cmd)
|
self.app.cx.input.complete(cmd)
|
||||||
|
|
|
||||||
|
|
@ -22,18 +22,18 @@ function M:preload()
|
||||||
return 0
|
return 0
|
||||||
end
|
end
|
||||||
|
|
||||||
local mimes, last = {}, ya.time()
|
local updates, last = {}, ya.time()
|
||||||
local flush = function(force)
|
local flush = function(force)
|
||||||
if not force and ya.time() - last < 0.3 then
|
if not force and ya.time() - last < 0.3 then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if next(mimes) then
|
if next(updates) then
|
||||||
ya.manager_emit("update_mimetype", {}, mimes)
|
ya.manager_emit("update_mimetype", { updates = updates })
|
||||||
mimes, last = {}, ya.time()
|
updates, last = {}, ya.time()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local i, j, mime = 1, 0, nil
|
local i, j, valid = 1, 0, nil
|
||||||
repeat
|
repeat
|
||||||
local line, event = child:read_line_with { timeout = 300 }
|
local line, event = child:read_line_with { timeout = 300 }
|
||||||
if event == 3 then
|
if event == 3 then
|
||||||
|
|
@ -43,11 +43,11 @@ function M:preload()
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
|
|
||||||
mime = match_mimetype(line)
|
valid = match_mimetype(line)
|
||||||
if mime and string.find(line, mime, 1, true) ~= 1 then
|
if valid and string.find(line, valid, 1, true) ~= 1 then
|
||||||
goto continue
|
goto continue
|
||||||
elseif mime then
|
elseif valid then
|
||||||
j, mimes[urls[i]] = j + 1, mime
|
j, updates[urls[i]] = j + 1, valid
|
||||||
flush(false)
|
flush(false)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
use mlua::{ExternalError, ExternalResult, Table, TableExt};
|
use mlua::{ExternalError, ExternalResult, Table, TableExt};
|
||||||
use tokio::runtime::Handle;
|
use tokio::runtime::Handle;
|
||||||
use yazi_dds::ValueSendable;
|
use yazi_dds::Sendable;
|
||||||
|
use yazi_shared::event::Data;
|
||||||
|
|
||||||
use super::slim_lua;
|
use super::slim_lua;
|
||||||
use crate::loader::LOADER;
|
use crate::loader::LOADER;
|
||||||
|
|
||||||
pub async fn entry(name: String, args: Vec<ValueSendable>) -> mlua::Result<()> {
|
pub async fn entry(name: String, args: Vec<Data>) -> mlua::Result<()> {
|
||||||
LOADER.ensure(&name).await.into_lua_err()?;
|
LOADER.ensure(&name).await.into_lua_err()?;
|
||||||
|
|
||||||
tokio::task::spawn_blocking(move || {
|
tokio::task::spawn_blocking(move || {
|
||||||
|
|
@ -16,7 +17,8 @@ pub async fn entry(name: String, args: Vec<ValueSendable>) -> mlua::Result<()> {
|
||||||
return Err("unloaded plugin".into_lua_err());
|
return Err("unloaded plugin".into_lua_err());
|
||||||
};
|
};
|
||||||
|
|
||||||
Handle::current().block_on(plugin.call_async_method("entry", args))
|
Handle::current()
|
||||||
|
.block_on(plugin.call_async_method("entry", Sendable::vec_to_table(&lua, args)))
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
.into_lua_err()?
|
.into_lua_err()?
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ use yazi_config::LAYOUT;
|
||||||
use yazi_shared::{emit, event::Cmd, Layer};
|
use yazi_shared::{emit, event::Cmd, Layer};
|
||||||
|
|
||||||
use super::slim_lua;
|
use super::slim_lua;
|
||||||
use crate::{bindings::{Cast, File, Window}, elements::Rect, loader::LOADER, OptData, LUA};
|
use crate::{bindings::{Cast, File, Window}, elements::Rect, loader::LOADER, Opt, OptCallback, LUA};
|
||||||
|
|
||||||
pub fn peek(cmd: &Cmd, file: yazi_shared::fs::File, skip: usize) -> CancellationToken {
|
pub fn peek(cmd: &Cmd, file: yazi_shared::fs::File, skip: usize) -> CancellationToken {
|
||||||
let ct = CancellationToken::new();
|
let ct = CancellationToken::new();
|
||||||
|
|
@ -56,18 +56,16 @@ pub fn peek(cmd: &Cmd, file: yazi_shared::fs::File, skip: usize) -> Cancellation
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn peek_sync(cmd: &Cmd, file: yazi_shared::fs::File, skip: usize) {
|
pub fn peek_sync(cmd: &Cmd, file: yazi_shared::fs::File, skip: usize) {
|
||||||
let data = OptData {
|
let cb: OptCallback = Box::new(move |_, plugin| {
|
||||||
cb: Some(Box::new(move |_, plugin| {
|
plugin.raw_set("file", File::cast(&LUA, file)?)?;
|
||||||
plugin.raw_set("file", File::cast(&LUA, file)?)?;
|
plugin.raw_set("skip", skip)?;
|
||||||
plugin.raw_set("skip", skip)?;
|
plugin.raw_set("area", Rect::cast(&LUA, LAYOUT.load().preview)?)?;
|
||||||
plugin.raw_set("area", Rect::cast(&LUA, LAYOUT.load().preview)?)?;
|
plugin.raw_set("window", Window::default())?;
|
||||||
plugin.raw_set("window", Window::default())?;
|
plugin.call_method("peek", ())
|
||||||
plugin.call_method("peek", ())
|
});
|
||||||
})),
|
|
||||||
..Default::default()
|
let cmd: Cmd =
|
||||||
};
|
Opt { name: cmd.name.to_owned(), sync: true, cb: Some(cb), ..Default::default() }.into();
|
||||||
emit!(Call(
|
|
||||||
Cmd::args("plugin", vec![cmd.name.to_owned()]).with_bool("sync", true).with_data(data),
|
emit!(Call(cmd.with_name("plugin"), Layer::App));
|
||||||
Layer::App
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,19 +2,17 @@ use mlua::TableExt;
|
||||||
use yazi_config::LAYOUT;
|
use yazi_config::LAYOUT;
|
||||||
use yazi_shared::{emit, event::Cmd, Layer};
|
use yazi_shared::{emit, event::Cmd, Layer};
|
||||||
|
|
||||||
use crate::{bindings::{Cast, File}, elements::Rect, OptData, LUA};
|
use crate::{bindings::{Cast, File}, elements::Rect, Opt, OptCallback, LUA};
|
||||||
|
|
||||||
pub fn seek_sync(cmd: &Cmd, file: yazi_shared::fs::File, units: i16) {
|
pub fn seek_sync(cmd: &Cmd, file: yazi_shared::fs::File, units: i16) {
|
||||||
let data = OptData {
|
let cb: OptCallback = Box::new(move |_, plugin| {
|
||||||
cb: Some(Box::new(move |_, plugin| {
|
plugin.raw_set("file", File::cast(&LUA, file)?)?;
|
||||||
plugin.raw_set("file", File::cast(&LUA, file)?)?;
|
plugin.raw_set("area", Rect::cast(&LUA, LAYOUT.load().preview)?)?;
|
||||||
plugin.raw_set("area", Rect::cast(&LUA, LAYOUT.load().preview)?)?;
|
plugin.call_method("seek", units)
|
||||||
plugin.call_method("seek", units)
|
});
|
||||||
})),
|
|
||||||
..Default::default()
|
let cmd: Cmd =
|
||||||
};
|
Opt { name: cmd.name.to_owned(), sync: true, cb: Some(cb), ..Default::default() }.into();
|
||||||
emit!(Call(
|
|
||||||
Cmd::args("plugin", vec![cmd.name.to_owned()]).with_bool("sync", true).with_data(data),
|
emit!(Call(cmd.with_name("plugin"), Layer::App));
|
||||||
Layer::App
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,34 +1,43 @@
|
||||||
use anyhow::bail;
|
use anyhow::bail;
|
||||||
use mlua::{Lua, Table};
|
use mlua::{Lua, Table};
|
||||||
use yazi_dds::ValueSendable;
|
use yazi_shared::event::{Cmd, Data};
|
||||||
use yazi_shared::event::Cmd;
|
|
||||||
|
|
||||||
|
pub(super) type OptCallback = Box<dyn FnOnce(&Lua, Table) -> mlua::Result<()> + Send>;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
pub struct Opt {
|
pub struct Opt {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub sync: bool,
|
pub sync: bool,
|
||||||
pub data: OptData,
|
pub args: Vec<Data>,
|
||||||
}
|
pub cb: Option<OptCallback>,
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct OptData {
|
|
||||||
pub args: Vec<ValueSendable>,
|
|
||||||
pub cb: Option<Box<dyn FnOnce(&Lua, Table) -> mlua::Result<()> + Send>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<Cmd> for Opt {
|
impl TryFrom<Cmd> for Opt {
|
||||||
type Error = anyhow::Error;
|
type Error = anyhow::Error;
|
||||||
|
|
||||||
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> {
|
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> {
|
||||||
let Some(name) = c.take_first().filter(|s| !s.is_empty()) else {
|
let Some(name) = c.take_first_str().filter(|s| !s.is_empty()) else {
|
||||||
bail!("plugin name cannot be empty");
|
bail!("plugin name cannot be empty");
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut data: OptData = c.take_data().unwrap_or_default();
|
let args = if let Some(s) = c.get_str("args") {
|
||||||
|
shell_words::split(s)?.into_iter().map(Data::String).collect()
|
||||||
|
} else {
|
||||||
|
c.take_any::<Vec<Data>>("args").unwrap_or_default()
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(args) = c.named.get("args") {
|
Ok(Self { name, sync: c.get_bool("sync"), args, cb: c.take_any("callback") })
|
||||||
data.args = shell_words::split(args)?.into_iter().map(ValueSendable::String).collect();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self { name, sync: c.named.contains_key("sync"), data })
|
impl From<Opt> for Cmd {
|
||||||
|
fn from(value: Opt) -> Self {
|
||||||
|
let mut cmd =
|
||||||
|
Cmd::args("", vec![value.name]).with_bool("sync", value.sync).with_any("args", value.args);
|
||||||
|
|
||||||
|
if let Some(cb) = value.cb {
|
||||||
|
cmd = cmd.with_any("callback", cb);
|
||||||
|
}
|
||||||
|
cmd
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,52 +1,27 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use mlua::{ExternalError, Lua, Table, Value};
|
use mlua::{ExternalError, Lua, Table, Value};
|
||||||
use yazi_dds::ValueSendable;
|
use yazi_dds::Sendable;
|
||||||
use yazi_shared::{emit, event::Cmd, render, Layer};
|
use yazi_shared::{emit, event::{Cmd, Data}, render, Layer};
|
||||||
|
|
||||||
use super::Utils;
|
use super::Utils;
|
||||||
|
|
||||||
impl Utils {
|
impl Utils {
|
||||||
fn parse_args(t: Table) -> mlua::Result<(Vec<String>, HashMap<String, String>)> {
|
fn parse_args(t: Table) -> mlua::Result<HashMap<String, Data>> {
|
||||||
let mut args = vec![];
|
let mut args = HashMap::with_capacity(t.raw_len());
|
||||||
let mut named = HashMap::new();
|
for pair in t.pairs::<Value, Value>() {
|
||||||
for result in t.pairs::<Value, Value>() {
|
let (k, v) = pair?;
|
||||||
let (k, v) = result?;
|
|
||||||
match k {
|
match k {
|
||||||
Value::Integer(_) => {
|
Value::Integer(i) if i > 0 => {
|
||||||
args.push(match v {
|
args.insert((i - 1).to_string(), Sendable::value_to_data(v)?);
|
||||||
Value::Integer(i) => i.to_string(),
|
|
||||||
Value::Number(n) => n.to_string(),
|
|
||||||
Value::String(s) => s.to_string_lossy().into_owned(),
|
|
||||||
_ => return Err("invalid value in cmd".into_lua_err()),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
Value::String(s) => {
|
Value::String(s) => {
|
||||||
let v = match v {
|
args.insert(s.to_str()?.replace('_', "-"), Sendable::value_to_data(v)?);
|
||||||
Value::Boolean(b) if b => String::new(),
|
|
||||||
Value::Boolean(b) if !b => continue,
|
|
||||||
Value::Integer(i) => i.to_string(),
|
|
||||||
Value::Number(n) => n.to_string(),
|
|
||||||
Value::String(s) => s.to_string_lossy().into_owned(),
|
|
||||||
_ => return Err("invalid value in cmd".into_lua_err()),
|
|
||||||
};
|
|
||||||
named.insert(s.to_str()?.replace('_', "-"), v);
|
|
||||||
}
|
}
|
||||||
_ => return Err("invalid key in cmd".into_lua_err()),
|
_ => return Err("invalid key in cmd".into_lua_err()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok((args, named))
|
Ok(args)
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn create_cmd(name: String, table: Table, data: Option<Value>) -> mlua::Result<Cmd> {
|
|
||||||
let (args, named) = Self::parse_args(table)?;
|
|
||||||
let mut cmd = Cmd { name, args, named, ..Default::default() };
|
|
||||||
|
|
||||||
if let Some(data) = data.and_then(|v| ValueSendable::try_from(v).ok()) {
|
|
||||||
cmd = cmd.with_data(data);
|
|
||||||
}
|
|
||||||
Ok(cmd)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn call(lua: &Lua, ya: &Table) -> mlua::Result<()> {
|
pub(super) fn call(lua: &Lua, ya: &Table) -> mlua::Result<()> {
|
||||||
|
|
@ -60,16 +35,16 @@ impl Utils {
|
||||||
|
|
||||||
ya.raw_set(
|
ya.raw_set(
|
||||||
"app_emit",
|
"app_emit",
|
||||||
lua.create_function(|_, (name, table, data): (String, Table, Option<Value>)| {
|
lua.create_function(|_, (name, args): (String, Table)| {
|
||||||
emit!(Call(Self::create_cmd(name, table, data)?, Layer::App));
|
emit!(Call(Cmd { name, args: Self::parse_args(args)? }, Layer::App));
|
||||||
Ok(())
|
Ok(())
|
||||||
})?,
|
})?,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
ya.raw_set(
|
ya.raw_set(
|
||||||
"manager_emit",
|
"manager_emit",
|
||||||
lua.create_function(|_, (name, table, data): (String, Table, Option<Value>)| {
|
lua.create_function(|_, (name, args): (String, Table)| {
|
||||||
emit!(Call(Self::create_cmd(name, table, data)?, Layer::Manager));
|
emit!(Call(Cmd { name, args: Self::parse_args(args)? }, Layer::Manager));
|
||||||
Ok(())
|
Ok(())
|
||||||
})?,
|
})?,
|
||||||
)?;
|
)?;
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ impl Utils {
|
||||||
let cand = cand?;
|
let cand = cand?;
|
||||||
cands.push(Control {
|
cands.push(Control {
|
||||||
on: Self::parse_keys(cand.raw_get("on")?)?,
|
on: Self::parse_keys(cand.raw_get("on")?)?,
|
||||||
run: vec![Cmd::args("callback", vec![i.to_string()]).with_data(tx.clone())],
|
run: vec![Cmd::args("callback", vec![i.to_string()]).with_any("tx", tx.clone())],
|
||||||
desc: cand.raw_get("desc").ok(),
|
desc: cand.raw_get("desc").ok(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -46,8 +46,8 @@ impl Utils {
|
||||||
emit!(Call(
|
emit!(Call(
|
||||||
Cmd::new("show")
|
Cmd::new("show")
|
||||||
.with("layer", Layer::Which)
|
.with("layer", Layer::Which)
|
||||||
.with_bool("silent", t.raw_get("silent").unwrap_or_default())
|
.with_any("candidates", cands)
|
||||||
.with_data(cands),
|
.with_bool("silent", t.raw_get("silent").unwrap_or_default()),
|
||||||
Layer::Which
|
Layer::Which
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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(Cmd::new("preview").with_data(lock), Layer::Manager));
|
emit!(Call(Cmd::new("preview").with_any("lock", 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(Cmd::new("preview").with_data(lock), Layer::Manager));
|
emit!(Call(Cmd::new("preview").with_any("lock", 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(Cmd::new("preview").with_data(lock), Layer::Manager));
|
emit!(Call(Cmd::new("preview").with_any("lock", lock), Layer::Manager));
|
||||||
Ok(())
|
Ok(())
|
||||||
})?,
|
})?,
|
||||||
)?;
|
)?;
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
use mlua::{ExternalError, ExternalResult, Function, IntoLua, Lua, Table, Value, Variadic};
|
use mlua::{ExternalError, ExternalResult, Function, IntoLua, Lua, Table, Value, Variadic};
|
||||||
use tokio::sync::oneshot;
|
use tokio::sync::oneshot;
|
||||||
use yazi_dds::ValueSendable;
|
use yazi_dds::Sendable;
|
||||||
use yazi_shared::{emit, event::Cmd, Layer};
|
use yazi_shared::{emit, event::{Cmd, Data}, Layer};
|
||||||
|
|
||||||
use super::Utils;
|
use super::Utils;
|
||||||
use crate::{loader::LOADER, runtime::RtRef, OptData};
|
use crate::{loader::LOADER, runtime::RtRef, OptCallback};
|
||||||
|
|
||||||
impl Utils {
|
impl Utils {
|
||||||
pub(super) fn sync(lua: &'static Lua, ya: &Table) -> mlua::Result<()> {
|
pub(super) fn sync(lua: &'static Lua, ya: &Table) -> mlua::Result<()> {
|
||||||
|
|
@ -37,7 +37,7 @@ impl Utils {
|
||||||
return Err("`ya.sync()` must be called in a plugin").into_lua_err();
|
return Err("`ya.sync()` must be called in a plugin").into_lua_err();
|
||||||
};
|
};
|
||||||
|
|
||||||
Self::retrieve(cur, block, args).await
|
Sendable::vec_to_variadic(lua, Self::retrieve(cur, block, args).await?)
|
||||||
})
|
})
|
||||||
})?,
|
})?,
|
||||||
)?;
|
)?;
|
||||||
|
|
@ -49,39 +49,37 @@ impl Utils {
|
||||||
name: String,
|
name: String,
|
||||||
calls: usize,
|
calls: usize,
|
||||||
args: Variadic<Value<'_>>,
|
args: Variadic<Value<'_>>,
|
||||||
) -> mlua::Result<mlua::Variadic<ValueSendable>> {
|
) -> mlua::Result<Vec<Data>> {
|
||||||
let args = ValueSendable::try_from_variadic(args)?;
|
let args = Sendable::variadic_to_vec(args)?;
|
||||||
let (tx, rx) = oneshot::channel::<Vec<ValueSendable>>();
|
let (tx, rx) = oneshot::channel::<Vec<Data>>();
|
||||||
|
|
||||||
let data = OptData {
|
let callback: OptCallback = {
|
||||||
cb: Some({
|
let name = name.clone();
|
||||||
let name = name.clone();
|
Box::new(move |lua, plugin| {
|
||||||
Box::new(move |lua, plugin| {
|
let Some(block) = lua.named_registry_value::<RtRef>("rt")?.get_block(&name, calls) else {
|
||||||
let Some(block) = lua.named_registry_value::<RtRef>("rt")?.get_block(&name, calls) else {
|
return Err("sync block not found".into_lua_err());
|
||||||
return Err("sync block not found".into_lua_err());
|
};
|
||||||
};
|
|
||||||
|
|
||||||
let mut self_args = Vec::with_capacity(args.len() + 1);
|
let mut self_args = Vec::with_capacity(args.len() + 1);
|
||||||
self_args.push(Value::Table(plugin));
|
self_args.push(Value::Table(plugin));
|
||||||
for arg in args {
|
for arg in args {
|
||||||
self_args.push(arg.into_lua(lua)?);
|
self_args.push(Sendable::data_to_value(lua, arg)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
let values =
|
let values = Sendable::variadic_to_vec(block.call(Variadic::from_iter(self_args))?)?;
|
||||||
ValueSendable::try_from_variadic(block.call(Variadic::from_iter(self_args))?)?;
|
tx.send(values).map_err(|_| "send failed".into_lua_err())
|
||||||
tx.send(values).map_err(|_| "send failed".into_lua_err())
|
})
|
||||||
})
|
|
||||||
}),
|
|
||||||
..Default::default()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
emit!(Call(
|
emit!(Call(
|
||||||
Cmd::args("plugin", vec![name.clone()]).with_bool("sync", true).with_data(data),
|
Cmd::args("plugin", vec![name.clone()])
|
||||||
|
.with_bool("sync", true)
|
||||||
|
.with_any("callback", callback),
|
||||||
Layer::App
|
Layer::App
|
||||||
));
|
));
|
||||||
|
|
||||||
Ok(Variadic::from_iter(rx.await.map_err(|_| {
|
rx.await.map_err(|_| {
|
||||||
format!("Failed to execute sync block-{calls} in `{name}` plugin").into_lua_err()
|
format!("Failed to execute sync block-{calls} in `{name}` plugin").into_lua_err()
|
||||||
})?))
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ impl AppProxy {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub async fn stop() {
|
pub async fn stop() {
|
||||||
let (tx, rx) = oneshot::channel::<()>();
|
let (tx, rx) = oneshot::channel::<()>();
|
||||||
emit!(Call(Cmd::new("stop").with_data(tx), Layer::App));
|
emit!(Call(Cmd::new("stop").with_any("tx", tx), Layer::App));
|
||||||
rx.await.ok();
|
rx.await.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -22,13 +22,13 @@ impl AppProxy {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn notify(opt: NotifyOpt) {
|
pub fn notify(opt: NotifyOpt) {
|
||||||
emit!(Call(Cmd::new("notify").with_data(opt), Layer::App));
|
emit!(Call(Cmd::new("notify").with_any("option", opt), Layer::App));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn notify_warn(title: &str, content: &str) {
|
pub fn notify_warn(title: &str, content: &str) {
|
||||||
emit!(Call(
|
emit!(Call(
|
||||||
Cmd::new("notify").with_data(NotifyOpt {
|
Cmd::new("notify").with_any("option", NotifyOpt {
|
||||||
title: title.to_owned(),
|
title: title.to_owned(),
|
||||||
content: content.to_owned(),
|
content: content.to_owned(),
|
||||||
level: NotifyLevel::Warn,
|
level: NotifyLevel::Warn,
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,13 @@ use tokio::sync::mpsc;
|
||||||
use yazi_config::popup::InputCfg;
|
use yazi_config::popup::InputCfg;
|
||||||
use yazi_shared::{emit, event::Cmd, InputError, Layer};
|
use yazi_shared::{emit, event::Cmd, InputError, Layer};
|
||||||
|
|
||||||
use crate::options::InputOpt;
|
|
||||||
|
|
||||||
pub struct InputProxy;
|
pub struct InputProxy;
|
||||||
|
|
||||||
impl InputProxy {
|
impl InputProxy {
|
||||||
#[inline]
|
#[inline]
|
||||||
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(Cmd::new("show").with_data(InputOpt { cfg, tx }), Layer::Input));
|
emit!(Call(Cmd::new("show").with_any("tx", tx).with_any("cfg", cfg), Layer::Input));
|
||||||
rx
|
rx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,13 +25,13 @@ impl ManagerProxy {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn open_do(opt: OpenDoOpt) {
|
pub fn open_do(opt: OpenDoOpt) {
|
||||||
emit!(Call(Cmd::new("open_do").with_data(opt), Layer::Manager));
|
emit!(Call(Cmd::new("open_do").with_any("option", opt), Layer::Manager));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn remove_do(targets: Vec<Url>, permanently: bool) {
|
pub fn remove_do(targets: Vec<Url>, permanently: bool) {
|
||||||
emit!(Call(
|
emit!(Call(
|
||||||
Cmd::new("remove_do").with_bool("permanently", permanently).with_data(targets),
|
Cmd::new("remove_do").with_bool("permanently", permanently).with_any("targets", targets),
|
||||||
Layer::Manager
|
Layer::Manager
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
use tokio::sync::mpsc;
|
|
||||||
use yazi_config::popup::InputCfg;
|
|
||||||
use yazi_shared::{event::Cmd, InputError};
|
|
||||||
|
|
||||||
pub struct InputOpt {
|
|
||||||
pub cfg: InputCfg,
|
|
||||||
pub tx: mpsc::UnboundedSender<Result<String, InputError>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<Cmd> for InputOpt {
|
|
||||||
type Error = ();
|
|
||||||
|
|
||||||
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> { c.take_data().ok_or(()) }
|
|
||||||
}
|
|
||||||
|
|
@ -1,11 +1,7 @@
|
||||||
mod input;
|
|
||||||
mod notify;
|
mod notify;
|
||||||
mod open;
|
mod open;
|
||||||
mod process;
|
mod process;
|
||||||
mod select;
|
|
||||||
|
|
||||||
pub use input::*;
|
|
||||||
pub use notify::*;
|
pub use notify::*;
|
||||||
pub use open::*;
|
pub use open::*;
|
||||||
pub use process::*;
|
pub use process::*;
|
||||||
pub use select::*;
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ pub struct NotifyOpt {
|
||||||
impl TryFrom<Cmd> for NotifyOpt {
|
impl TryFrom<Cmd> for NotifyOpt {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> { c.take_data().ok_or(()) }
|
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> { c.take_any("option").ok_or(()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TryFrom<mlua::Table<'a>> for NotifyOpt {
|
impl<'a> TryFrom<mlua::Table<'a>> for NotifyOpt {
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ pub struct OpenDoOpt {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Cmd> for OpenDoOpt {
|
impl From<Cmd> for OpenDoOpt {
|
||||||
fn from(mut c: Cmd) -> Self { c.take_data().unwrap_or_default() }
|
fn from(mut c: Cmd) -> Self { c.take_any("option").unwrap_or_default() }
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Open with
|
// --- Open with
|
||||||
|
|
@ -24,5 +24,5 @@ pub struct OpenWithOpt {
|
||||||
impl TryFrom<Cmd> for OpenWithOpt {
|
impl TryFrom<Cmd> for OpenWithOpt {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> { c.take_data().ok_or(()) }
|
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> { c.take_any("option").ok_or(()) }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,5 +14,5 @@ pub struct ProcessExecOpt {
|
||||||
impl TryFrom<Cmd> for ProcessExecOpt {
|
impl TryFrom<Cmd> for ProcessExecOpt {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> { c.take_data().ok_or(()) }
|
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> { c.take_any("option").ok_or(()) }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
use tokio::sync::oneshot;
|
|
||||||
use yazi_config::popup::SelectCfg;
|
|
||||||
use yazi_shared::event::Cmd;
|
|
||||||
|
|
||||||
pub struct SelectOpt {
|
|
||||||
pub cfg: SelectCfg,
|
|
||||||
pub tx: oneshot::Sender<anyhow::Result<usize>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<Cmd> for SelectOpt {
|
|
||||||
type Error = ();
|
|
||||||
|
|
||||||
fn try_from(mut c: Cmd) -> Result<Self, Self::Error> { c.take_data().ok_or(()) }
|
|
||||||
}
|
|
||||||
|
|
@ -2,15 +2,13 @@ use tokio::sync::oneshot;
|
||||||
use yazi_config::popup::SelectCfg;
|
use yazi_config::popup::SelectCfg;
|
||||||
use yazi_shared::{emit, event::Cmd, Layer};
|
use yazi_shared::{emit, event::Cmd, Layer};
|
||||||
|
|
||||||
use crate::options::SelectOpt;
|
|
||||||
|
|
||||||
pub struct SelectProxy;
|
pub struct SelectProxy;
|
||||||
|
|
||||||
impl SelectProxy {
|
impl SelectProxy {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub async fn show(cfg: SelectCfg) -> anyhow::Result<usize> {
|
pub async fn show(cfg: SelectCfg) -> anyhow::Result<usize> {
|
||||||
let (tx, rx) = oneshot::channel();
|
let (tx, rx) = oneshot::channel();
|
||||||
emit!(Call(Cmd::new("show").with_data(SelectOpt { cfg, tx }), Layer::Select));
|
emit!(Call(Cmd::new("show").with_any("tx", tx).with_any("cfg", cfg), Layer::Select));
|
||||||
rx.await?
|
rx.await?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,14 +11,17 @@ pub struct TasksProxy;
|
||||||
impl TasksProxy {
|
impl TasksProxy {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn open_with(targets: Vec<Url>, opener: Cow<'static, Opener>) {
|
pub fn open_with(targets: Vec<Url>, opener: Cow<'static, Opener>) {
|
||||||
emit!(Call(Cmd::new("open_with").with_data(OpenWithOpt { targets, opener }), Layer::Tasks));
|
emit!(Call(
|
||||||
|
Cmd::new("open_with").with_any("option", OpenWithOpt { targets, opener }),
|
||||||
|
Layer::Tasks
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub async fn process_exec(args: Vec<OsString>, opener: Cow<'static, Opener>) {
|
pub async fn process_exec(args: Vec<OsString>, opener: Cow<'static, Opener>) {
|
||||||
let (tx, rx) = oneshot::channel();
|
let (tx, rx) = oneshot::channel();
|
||||||
emit!(Call(
|
emit!(Call(
|
||||||
Cmd::new("process_exec").with_data(ProcessExecOpt { args, opener, done: tx }),
|
Cmd::new("process_exec").with_any("option", ProcessExecOpt { args, opener, done: tx }),
|
||||||
Layer::Tasks
|
Layer::Tasks
|
||||||
));
|
));
|
||||||
rx.await.ok();
|
rx.await.ok();
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use std::{borrow::Cow, collections::VecDeque, fs::Metadata, path::{Path, PathBuf}};
|
use std::{borrow::Cow, collections::VecDeque, fs::Metadata, path::{Path, PathBuf}};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::{anyhow, Result};
|
||||||
use futures::{future::BoxFuture, FutureExt};
|
use futures::{future::BoxFuture, FutureExt};
|
||||||
use tokio::{fs, io::{self, ErrorKind::{AlreadyExists, NotFound}}, sync::mpsc};
|
use tokio::{fs, io::{self, ErrorKind::{AlreadyExists, NotFound}}, sync::mpsc};
|
||||||
use tracing::warn;
|
use tracing::warn;
|
||||||
|
|
@ -51,9 +51,10 @@ impl File {
|
||||||
if task.retry < TASKS.bizarre_retry
|
if task.retry < TASKS.bizarre_retry
|
||||||
&& matches!(e.raw_os_error(), Some(1) | Some(93)) =>
|
&& matches!(e.raw_os_error(), Some(1) | Some(93)) =>
|
||||||
{
|
{
|
||||||
self.log(task.id, format!("Paste task retry: {:?}", task))?;
|
|
||||||
task.retry += 1;
|
task.retry += 1;
|
||||||
return Ok(self.macro_.send(FileOp::Paste(task).into(), LOW).await?);
|
self.log(task.id, format!("Paste task retry: {:?}", task))?;
|
||||||
|
self.queue(FileOp::Paste(task), LOW).await?;
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
Err(e) => Err(e)?,
|
Err(e) => Err(e)?,
|
||||||
}
|
}
|
||||||
|
|
@ -147,9 +148,9 @@ impl File {
|
||||||
self.prog.send(TaskProg::New(id, meta.len()))?;
|
self.prog.send(TaskProg::New(id, meta.len()))?;
|
||||||
|
|
||||||
if meta.is_file() {
|
if meta.is_file() {
|
||||||
self.macro_.send(FileOp::Paste(task).into(), LOW).await?;
|
self.queue(FileOp::Paste(task), LOW).await?;
|
||||||
} else if meta.is_symlink() {
|
} else if meta.is_symlink() {
|
||||||
self.macro_.send(FileOp::Link(task.to_link(meta)).into(), NORMAL).await?;
|
self.queue(FileOp::Link(task.to_link(meta)), NORMAL).await?;
|
||||||
}
|
}
|
||||||
return self.succ(id);
|
return self.succ(id);
|
||||||
}
|
}
|
||||||
|
|
@ -193,9 +194,9 @@ impl File {
|
||||||
self.prog.send(TaskProg::New(task.id, meta.len()))?;
|
self.prog.send(TaskProg::New(task.id, meta.len()))?;
|
||||||
|
|
||||||
if meta.is_file() {
|
if meta.is_file() {
|
||||||
self.macro_.send(FileOp::Paste(task.clone()).into(), LOW).await?;
|
self.queue(FileOp::Paste(task.clone()), LOW).await?;
|
||||||
} else if meta.is_symlink() {
|
} else if meta.is_symlink() {
|
||||||
self.macro_.send(FileOp::Link(task.to_link(meta)).into(), NORMAL).await?;
|
self.queue(FileOp::Link(task.to_link(meta)), NORMAL).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -209,7 +210,7 @@ impl File {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.prog.send(TaskProg::New(id, task.meta.as_ref().unwrap().len()))?;
|
self.prog.send(TaskProg::New(id, task.meta.as_ref().unwrap().len()))?;
|
||||||
self.macro_.send(FileOp::Link(task).into(), NORMAL).await?;
|
self.queue(FileOp::Link(task), NORMAL).await?;
|
||||||
self.succ(id)
|
self.succ(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -219,7 +220,7 @@ impl File {
|
||||||
let id = task.id;
|
let id = task.id;
|
||||||
task.length = meta.len();
|
task.length = meta.len();
|
||||||
self.prog.send(TaskProg::New(id, meta.len()))?;
|
self.prog.send(TaskProg::New(id, meta.len()))?;
|
||||||
self.macro_.send(FileOp::Delete(task).into(), NORMAL).await?;
|
self.queue(FileOp::Delete(task), NORMAL).await?;
|
||||||
return self.succ(id);
|
return self.succ(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -238,7 +239,7 @@ impl File {
|
||||||
task.target = Url::from(entry.path());
|
task.target = Url::from(entry.path());
|
||||||
task.length = meta.len();
|
task.length = meta.len();
|
||||||
self.prog.send(TaskProg::New(task.id, meta.len()))?;
|
self.prog.send(TaskProg::New(task.id, meta.len()))?;
|
||||||
self.macro_.send(FileOp::Delete(task.clone()).into(), NORMAL).await?;
|
self.queue(FileOp::Delete(task.clone()), NORMAL).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.succ(task.id)
|
self.succ(task.id)
|
||||||
|
|
@ -249,7 +250,7 @@ impl File {
|
||||||
task.length = calculate_size(&task.target).await;
|
task.length = calculate_size(&task.target).await;
|
||||||
|
|
||||||
self.prog.send(TaskProg::New(id, task.length))?;
|
self.prog.send(TaskProg::New(id, task.length))?;
|
||||||
self.macro_.send(FileOp::Trash(task).into(), LOW).await?;
|
self.queue(FileOp::Trash(task), LOW).await?;
|
||||||
self.succ(id)
|
self.succ(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -296,6 +297,11 @@ impl File {
|
||||||
fn log(&self, id: usize, line: String) -> Result<()> {
|
fn log(&self, id: usize, line: String) -> Result<()> {
|
||||||
Ok(self.prog.send(TaskProg::Log(id, line))?)
|
Ok(self.prog.send(TaskProg::Log(id, line))?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
async fn queue(&self, op: impl Into<TaskOp>, priority: u8) -> Result<()> {
|
||||||
|
self.macro_.send(op.into(), priority).await.map_err(|_| anyhow!("Failed to send task"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FileOpPaste {
|
impl FileOpPaste {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use yazi_dds::ValueSendable;
|
use yazi_shared::event::Data;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum PluginOp {
|
pub enum PluginOp {
|
||||||
|
|
@ -17,5 +17,5 @@ impl PluginOp {
|
||||||
pub struct PluginOpEntry {
|
pub struct PluginOpEntry {
|
||||||
pub id: usize,
|
pub id: usize,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub args: Vec<ValueSendable>,
|
pub args: Vec<Data>,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use anyhow::Result;
|
use anyhow::{anyhow, Result};
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
use yazi_plugin::isolate;
|
use yazi_plugin::isolate;
|
||||||
|
|
||||||
|
|
@ -43,7 +43,7 @@ impl Plugin {
|
||||||
let id = task.id;
|
let id = task.id;
|
||||||
|
|
||||||
self.prog.send(TaskProg::New(id, 0))?;
|
self.prog.send(TaskProg::New(id, 0))?;
|
||||||
self.macro_.try_send(PluginOp::Entry(task).into(), HIGH)?;
|
self.queue(PluginOp::Entry(task), HIGH)?;
|
||||||
self.succ(id)
|
self.succ(id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -56,4 +56,9 @@ impl Plugin {
|
||||||
fn fail(&self, id: usize, reason: String) -> Result<()> {
|
fn fail(&self, id: usize, reason: String) -> Result<()> {
|
||||||
Ok(self.prog.send(TaskProg::Fail(id, reason))?)
|
Ok(self.prog.send(TaskProg::Fail(id, reason))?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn queue(&self, op: impl Into<TaskOp>, priority: u8) -> Result<()> {
|
||||||
|
self.macro_.try_send(op.into(), priority).map_err(|_| anyhow!("Failed to send task"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::{anyhow, Result};
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::mpsc;
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
|
|
@ -73,8 +73,8 @@ impl Preload {
|
||||||
self.prog.send(TaskProg::New(id, 0))?;
|
self.prog.send(TaskProg::New(id, 0))?;
|
||||||
|
|
||||||
match task.plugin.prio {
|
match task.plugin.prio {
|
||||||
Priority::Low => self.macro_.send(PreloadOp::Rule(task).into(), NORMAL).await?,
|
Priority::Low => self.queue(PreloadOp::Rule(task), NORMAL).await?,
|
||||||
Priority::Normal => self.macro_.send(PreloadOp::Rule(task).into(), HIGH).await?,
|
Priority::Normal => self.queue(PreloadOp::Rule(task), HIGH).await?,
|
||||||
Priority::High => self.work(PreloadOp::Rule(task)).await?,
|
Priority::High => self.work(PreloadOp::Rule(task)).await?,
|
||||||
}
|
}
|
||||||
self.succ(id)
|
self.succ(id)
|
||||||
|
|
@ -97,4 +97,9 @@ impl Preload {
|
||||||
fn fail(&self, id: usize, reason: String) -> Result<()> {
|
fn fail(&self, id: usize, reason: String) -> Result<()> {
|
||||||
Ok(self.prog.send(TaskProg::Fail(id, reason))?)
|
Ok(self.prog.send(TaskProg::Fail(id, reason))?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
async fn queue(&self, op: impl Into<TaskOp>, priority: u8) -> Result<()> {
|
||||||
|
self.macro_.send(op.into(), priority).await.map_err(|_| anyhow!("Failed to send task"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ use futures::{future::BoxFuture, FutureExt};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use tokio::{fs, select, sync::{mpsc::{self, UnboundedReceiver}, oneshot}, task::JoinHandle};
|
use tokio::{fs, select, sync::{mpsc::{self, UnboundedReceiver}, oneshot}, task::JoinHandle};
|
||||||
use yazi_config::{open::Opener, plugin::PluginRule, TASKS};
|
use yazi_config::{open::Opener, plugin::PluginRule, TASKS};
|
||||||
use yazi_dds::{Pump, ValueSendable};
|
use yazi_dds::Pump;
|
||||||
use yazi_shared::{fs::{unique_path, Url}, Throttle};
|
use yazi_shared::{event::Data, fs::{unique_path, Url}, Throttle};
|
||||||
|
|
||||||
use super::{Ongoing, TaskProg, TaskStage};
|
use super::{Ongoing, TaskProg, TaskStage};
|
||||||
use crate::{file::{File, FileOpDelete, FileOpLink, FileOpPaste, FileOpTrash}, plugin::{Plugin, PluginOpEntry}, preload::{Preload, PreloadOpRule, PreloadOpSize}, process::{Process, ProcessOpBg, ProcessOpBlock, ProcessOpOrphan}, TaskKind, TaskOp, HIGH, LOW, NORMAL};
|
use crate::{file::{File, FileOpDelete, FileOpLink, FileOpPaste, FileOpTrash}, plugin::{Plugin, PluginOpEntry}, preload::{Preload, PreloadOpRule, PreloadOpSize}, process::{Process, ProcessOpBg, ProcessOpBlock, ProcessOpOrphan}, TaskKind, TaskOp, HIGH, LOW, NORMAL};
|
||||||
|
|
@ -182,7 +182,7 @@ impl Scheduler {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn plugin_micro(&self, name: String, args: Vec<ValueSendable>) {
|
pub fn plugin_micro(&self, name: String, args: Vec<Data>) {
|
||||||
let id = self.ongoing.lock().add(TaskKind::User, format!("Run micro plugin `{name}`"));
|
let id = self.ongoing.lock().add(TaskKind::User, format!("Run micro plugin `{name}`"));
|
||||||
|
|
||||||
let plugin = self.plugin.clone();
|
let plugin = self.plugin.clone();
|
||||||
|
|
@ -195,7 +195,7 @@ impl Scheduler {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn plugin_macro(&self, name: String, args: Vec<ValueSendable>) {
|
pub fn plugin_macro(&self, name: String, args: Vec<Data>) {
|
||||||
let id = self.ongoing.lock().add(TaskKind::User, format!("Run macro plugin `{name}`"));
|
let id = self.ongoing.lock().add(TaskKind::User, format!("Run macro plugin `{name}`"));
|
||||||
|
|
||||||
self.plugin.macro_(PluginOpEntry { id, name, args }).ok();
|
self.plugin.macro_(PluginOpEntry { id, name, args }).ok();
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
use std::{any::Any, collections::HashMap, fmt::{self, Display}, mem};
|
use std::{any::Any, collections::HashMap, fmt::{self, Display}};
|
||||||
|
|
||||||
|
use super::Data;
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct Cmd {
|
pub struct Cmd {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub args: Vec<String>,
|
pub args: HashMap<String, Data>,
|
||||||
pub named: HashMap<String, String>,
|
|
||||||
pub data: Option<Box<dyn Any + Send>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cmd {
|
impl Cmd {
|
||||||
|
|
@ -14,49 +14,70 @@ impl Cmd {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn args(name: &str, args: Vec<String>) -> Self {
|
pub fn args(name: &str, args: Vec<String>) -> Self {
|
||||||
Self { name: name.to_owned(), args, ..Default::default() }
|
Self {
|
||||||
|
name: name.to_owned(),
|
||||||
|
args: args.into_iter().enumerate().map(|(i, s)| (i.to_string(), Data::String(s))).collect(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[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.args.insert(name.to_string(), Data::String(value.to_string()));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn with_bool(mut self, name: impl ToString, state: bool) -> Self {
|
pub fn with_bool(mut self, name: impl ToString, state: bool) -> Self {
|
||||||
if state {
|
self.args.insert(name.to_string(), Data::Boolean(state));
|
||||||
self.named.insert(name.to_string(), Default::default());
|
|
||||||
}
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn with_data(mut self, data: impl Any + Send) -> Self {
|
pub fn with_any(mut self, name: impl ToString, data: impl Any + Send) -> Self {
|
||||||
self.data = Some(Box::new(data));
|
self.args.insert(name.to_string(), Data::Any(Box::new(data)));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn take_data<T: 'static>(&mut self) -> Option<T> {
|
pub fn with_name(mut self, name: impl ToString) -> Self {
|
||||||
self.data.take().and_then(|d| d.downcast::<T>().ok()).map(|d| *d)
|
self.name = name.to_string();
|
||||||
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn take_first(&mut self) -> Option<String> {
|
pub fn get_str(&self, name: &str) -> Option<&str> { self.args.get(name).and_then(Data::as_str) }
|
||||||
if self.args.is_empty() { None } else { Some(mem::take(&mut self.args[0])) }
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_bool(&self, name: &str) -> bool {
|
||||||
|
self.args.get(name).and_then(Data::as_bool).unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn take_name(&mut self, name: &str) -> Option<String> { self.named.remove(name) }
|
pub fn take_data(&mut self, name: &str) -> Option<Data> { self.args.remove(name) }
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn clone_without_data(&self) -> Self {
|
pub fn take_str(&mut self, name: &str) -> Option<String> {
|
||||||
|
if let Some(Data::String(s)) = self.args.remove(name) { Some(s) } else { None }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn take_first_str(&mut self) -> Option<String> {
|
||||||
|
if let Some(Data::String(s)) = self.args.remove("0") { Some(s) } else { None }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn take_any<T: 'static>(&mut self, name: &str) -> Option<T> {
|
||||||
|
self.args.remove(name).and_then(|d| d.into_any())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn shallow_clone(&self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: self.name.clone(),
|
name: self.name.clone(),
|
||||||
args: self.args.clone(),
|
args: self
|
||||||
named: self.named.clone(),
|
.args
|
||||||
data: None,
|
.iter()
|
||||||
|
.filter_map(|(k, v)| v.shallow_clone().map(|v| (k.clone(), v)))
|
||||||
|
.collect(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -64,13 +85,15 @@ impl Cmd {
|
||||||
impl Display for Cmd {
|
impl Display for Cmd {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "{}", self.name)?;
|
write!(f, "{}", self.name)?;
|
||||||
if !self.args.is_empty() {
|
for (k, v) in &self.args {
|
||||||
write!(f, " {}", self.args.join(" "))?;
|
if k.as_bytes().first().is_some_and(|b| b.is_ascii_digit()) {
|
||||||
}
|
if let Some(s) = v.as_str() {
|
||||||
for (k, v) in &self.named {
|
write!(f, " {s}")?;
|
||||||
write!(f, " --{k}")?;
|
}
|
||||||
if !v.is_empty() {
|
} else if v.as_bool().is_some_and(|b| b) {
|
||||||
write!(f, "={v}")?;
|
write!(f, " --{k}")?;
|
||||||
|
} else if let Some(s) = v.as_str() {
|
||||||
|
write!(f, " --{k}={s}")?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
96
yazi-shared/src/event/data.rs
Normal file
96
yazi-shared/src/event/data.rs
Normal file
|
|
@ -0,0 +1,96 @@
|
||||||
|
use std::{any::Any, collections::HashMap};
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::{fs::Url, OrderedFloat};
|
||||||
|
|
||||||
|
// --- Data
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum Data {
|
||||||
|
Nil,
|
||||||
|
Boolean(bool),
|
||||||
|
Integer(i64),
|
||||||
|
Number(f64),
|
||||||
|
String(String),
|
||||||
|
Table(HashMap<DataKey, Data>),
|
||||||
|
#[serde(skip)]
|
||||||
|
Url(Url),
|
||||||
|
#[serde(skip)]
|
||||||
|
Any(Box<dyn Any + Send>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Data {
|
||||||
|
#[inline]
|
||||||
|
pub fn as_bool(&self) -> Option<bool> {
|
||||||
|
match self {
|
||||||
|
Self::Boolean(b) => Some(*b),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn as_str(&self) -> Option<&str> {
|
||||||
|
match self {
|
||||||
|
Self::String(s) => Some(s),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn as_any<T: 'static>(&self) -> Option<&T> {
|
||||||
|
match self {
|
||||||
|
Self::Any(b) => b.downcast_ref::<T>(),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn into_any<T: 'static>(self) -> Option<T> {
|
||||||
|
match self {
|
||||||
|
Self::Any(b) => b.downcast::<T>().ok().map(|b| *b),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_table_string(self) -> HashMap<String, String> {
|
||||||
|
let Self::Table(table) = self else {
|
||||||
|
return Default::default();
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut map = HashMap::with_capacity(table.len());
|
||||||
|
for pair in table {
|
||||||
|
if let (DataKey::String(k), Self::String(v)) = pair {
|
||||||
|
map.insert(k, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
map
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn shallow_clone(&self) -> Option<Self> {
|
||||||
|
match self {
|
||||||
|
Self::Boolean(b) => Some(Self::Boolean(*b)),
|
||||||
|
Self::String(s) => Some(Self::String(s.clone())),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Key
|
||||||
|
#[derive(Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum DataKey {
|
||||||
|
Nil,
|
||||||
|
Boolean(bool),
|
||||||
|
Integer(i64),
|
||||||
|
Number(OrderedFloat),
|
||||||
|
String(String),
|
||||||
|
#[serde(skip)]
|
||||||
|
Url(Url),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DataKey {
|
||||||
|
#[inline]
|
||||||
|
pub fn is_numeric(&self) -> bool { matches!(self, Self::Integer(_) | Self::Number(_)) }
|
||||||
|
}
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
#![allow(clippy::module_inception)]
|
#![allow(clippy::module_inception)]
|
||||||
|
|
||||||
mod cmd;
|
mod cmd;
|
||||||
|
mod data;
|
||||||
mod event;
|
mod event;
|
||||||
mod render;
|
mod render;
|
||||||
|
|
||||||
pub use cmd::*;
|
pub use cmd::*;
|
||||||
|
pub use data::*;
|
||||||
pub use event::*;
|
pub use event::*;
|
||||||
pub use render::*;
|
pub use render::*;
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ impl FilesOp {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn emit(self) {
|
pub fn emit(self) {
|
||||||
emit!(Call(Cmd::new("update_files").with_data(self), Layer::Manager));
|
emit!(Call(Cmd::new("update_files").with_any("op", self), Layer::Manager));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prepare(url: &Url) -> u64 {
|
pub fn prepare(url: &Url) -> u64 {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue