This commit is contained in:
sxyazi 2026-04-04 21:10:44 +08:00
parent 17ce4bf3a9
commit c176de9a30
No known key found for this signature in database
13 changed files with 81 additions and 53 deletions

View file

@ -4,11 +4,10 @@ use scopeguard::defer;
use tracing::{error, warn};
use yazi_binding::runtime_mut;
use yazi_core::app::PluginMode;
use yazi_dds::Sendable;
use yazi_macro::succ;
use yazi_parser::app::PluginForm;
use yazi_plugin::LUA;
use yazi_runner::loader::{LOADER, Loader};
use yazi_runner::{entry::EntryJob, loader::{LOADER, Loader}};
use yazi_scheduler::NotifyProxy;
use yazi_shared::data::Data;
@ -48,8 +47,7 @@ impl Actor for PluginDo {
if let Some(cb) = opt.callback {
cb(&LUA, plugin)
} else {
let job = LUA.create_table_from([("args", Sendable::args_to_table(&LUA, opt.args)?)])?;
plugin.call_method("entry", job)
plugin.call_method("entry", EntryJob { args: opt.args, ..Default::default() })
}
});
if let Err(ref e) = result {

View file

@ -11,8 +11,8 @@ impl From<FetchProg> for TaskSummary {
fn from(value: FetchProg) -> Self {
Self {
total: 1,
success: (value.state == Some(true)) as u32,
failed: (value.state == Some(false)) as u32,
success: value.success() as u32,
failed: value.failed() as u32,
percent: value.percent().map(Into::into),
}
}

View file

@ -119,8 +119,8 @@ impl From<FileProgLink> for TaskSummary {
fn from(value: FileProgLink) -> Self {
Self {
total: 1,
success: (value.state == Some(true)) as u32,
failed: (value.state == Some(false)) as u32,
success: value.success() as u32,
failed: value.failed() as u32,
percent: value.percent().map(Into::into),
}
}
@ -243,8 +243,8 @@ impl From<FileProgTrash> for TaskSummary {
fn from(value: FileProgTrash) -> Self {
Self {
total: 1,
success: (value.state == Some(true)) as u32,
failed: (value.state == Some(false)) as u32,
success: value.success() as u32,
failed: value.failed() as u32,
percent: value.percent().map(Into::into),
}
}

View file

@ -6,11 +6,12 @@ use yazi_dds::Pump;
use yazi_fs::ok_or_not_found;
use yazi_vfs::provider;
use crate::{Ongoing, TaskOp, TaskOps, TasksProxy, file::{FileOutCopy, FileOutCut, FileOutDelete, FileOutDownload, FileOutHardlink, FileOutLink, FileOutTrash, FileOutUpload}, hook::{HookIn, HookInDelete, HookInDownload, HookInOutCopy, HookInOutCut, HookInOutHardlink, HookInOutLink, HookInTrash, HookInUpload}};
use crate::{Ongoing, TaskOp, TaskOps, TasksProxy, file::{FileOutCopy, FileOutCut, FileOutDelete, FileOutDownload, FileOutHardlink, FileOutLink, FileOutTrash, FileOutUpload}, hook::{HookIn, HookInDelete, HookInDownload, HookInOutCopy, HookInOutCut, HookInOutHardlink, HookInOutLink, HookInPreload, HookInTrash, HookInUpload}, preload::{Preload, PreloadOut}};
pub(crate) struct Hook {
ops: TaskOps,
ongoing: Arc<Mutex<Ongoing>>,
preload: Arc<Preload>,
tx: async_priority_channel::Sender<HookIn, u8>,
}
@ -18,9 +19,10 @@ impl Hook {
pub(crate) fn new(
ops: &mpsc::UnboundedSender<TaskOp>,
ongoing: &Arc<Mutex<Ongoing>>,
preload: &Arc<Preload>,
tx: async_priority_channel::Sender<HookIn, u8>,
) -> Self {
Self { ops: ops.into(), ongoing: ongoing.clone(), tx }
Self { ops: ops.into(), ongoing: ongoing.clone(), preload: preload.clone(), tx }
}
// --- File
@ -98,6 +100,15 @@ impl Hook {
}
self.ops.out(task.id, FileOutUpload::Clean);
}
// --- Preload
pub(crate) async fn preload(&self, task: HookInPreload) {
if !self.ongoing.lock().intact(task.id) {
self.preload.loaded.lock().get_mut(&task.hash).map(|x| *x &= !(1 << task.idx));
}
self.ops.out(task.id, PreloadOut::Clean);
}
}
impl Hook {

View file

@ -12,6 +12,7 @@ pub(crate) enum HookIn {
Hardlink(HookInOutHardlink),
Download(HookInDownload),
Upload(HookInUpload),
Preload(HookInPreload),
}
impl_from_in!(
@ -23,6 +24,7 @@ impl_from_in!(
Hardlink(HookInOutHardlink),
Download(HookInDownload),
Upload(HookInUpload),
Preload(HookInPreload),
);
impl HookIn {
@ -36,6 +38,7 @@ impl HookIn {
Self::Hardlink(r#in) => r#in.id,
Self::Download(r#in) => r#in.id,
Self::Upload(r#in) => r#in.id,
Self::Preload(r#in) => r#in.id,
}
}
@ -49,6 +52,7 @@ impl HookIn {
Self::Hardlink(r#in) => Self::Hardlink(HookInOutHardlink { id, ..r#in }),
Self::Download(r#in) => Self::Download(HookInDownload { id, ..r#in }),
Self::Upload(r#in) => Self::Upload(HookInUpload { id, ..r#in }),
Self::Preload(r#in) => Self::Preload(HookInPreload { id, ..r#in }),
}
}
}
@ -210,3 +214,15 @@ impl HookInUpload {
Self { id: Id::ZERO, target: target.into() }
}
}
// --- Preload
#[derive(Debug)]
pub(crate) struct HookInPreload {
pub(crate) id: Id,
pub(crate) idx: u8,
pub(crate) hash: u64,
}
impl HookInPreload {
pub(crate) fn new(idx: u8, hash: u64) -> Self { Self { id: Id::ZERO, idx, hash } }
}

View file

@ -12,8 +12,8 @@ impl From<PluginProgEntry> for TaskSummary {
fn from(value: PluginProgEntry) -> Self {
Self {
total: 1,
success: (value.state == Some(true)) as u32,
failed: (value.state == Some(false)) as u32,
success: value.success() as u32,
failed: value.failed() as u32,
percent: value.percent().map(Into::into),
}
}

View file

@ -1,10 +1,9 @@
use yazi_config::plugin::Preloader;
use yazi_shared::{CompletionToken, Id};
use yazi_shared::Id;
#[derive(Clone, Debug)]
pub(crate) struct PreloadIn {
pub(crate) id: Id,
pub(crate) plugin: &'static Preloader,
pub(crate) target: yazi_fs::File,
pub(crate) done: CompletionToken,
}

View file

@ -6,6 +6,7 @@ use crate::{Task, TaskProg};
pub(crate) enum PreloadOut {
Succ,
Fail(String),
Clean,
}
impl From<PreloadError> for PreloadOut {
@ -23,6 +24,9 @@ impl PreloadOut {
prog.state = Some(false);
task.log(reason);
}
Self::Clean => {
prog.cleaned = Some(true);
}
}
}
}

View file

@ -8,7 +8,6 @@ use tracing::error;
use yazi_config::Priority;
use yazi_fs::FsHash64;
use yazi_runner::{RUNNER, preloader::{PreloadError, PreloadJob}};
use yazi_shared::CompletionToken;
use crate::{HIGH, LOW, NORMAL, TaskOp, TaskOps, preload::{PreloadIn, PreloadOut}};
@ -17,7 +16,7 @@ pub struct Preload {
tx: async_priority_channel::Sender<PreloadIn, u8>,
pub loaded: Mutex<LruCache<u64, u16>>,
pub loading: Mutex<LruCache<u64, CompletionToken>>,
pub loading: Mutex<LruCache<u64, yazi_shared::Id>>,
}
impl Preload {
@ -35,12 +34,7 @@ impl Preload {
}
pub(crate) async fn preload(&self, task: PreloadIn) -> Result<(), PreloadOut> {
let url_hash = task.target.url.hash_u64();
let file_hash = task.target.hash_u64();
if let Some(prev) = self.loading.lock().put(url_hash, task.done) {
prev.complete(false);
}
let hash = task.target.hash_u64();
let mut rx = RUNNER.preload(PreloadJob { action: &task.plugin.run, file: task.target }).await;
let state = match rx.recv().await.unwrap_or(Err(PreloadError::Cancelled)) {
@ -50,7 +44,7 @@ impl Preload {
};
if !state.complete {
self.loaded.lock().get_mut(&file_hash).map(|x| *x &= !(1 << task.plugin.idx));
self.loaded.lock().get_mut(&hash).map(|x| *x &= !(1 << task.plugin.idx));
}
if let Some(e) = state.error {
error!("Error when running preloader `{}`:\n{e}", task.plugin.run.name);

View file

@ -4,15 +4,16 @@ use crate::TaskSummary;
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize)]
pub struct PreloadProg {
pub state: Option<bool>,
pub state: Option<bool>,
pub cleaned: Option<bool>,
}
impl From<PreloadProg> for TaskSummary {
fn from(value: PreloadProg) -> Self {
Self {
total: 1,
success: (value.state == Some(true)) as u32,
failed: (value.state == Some(false)) as u32,
success: value.success() as u32,
failed: value.failed() as u32,
percent: value.percent().map(Into::into),
}
}
@ -21,13 +22,13 @@ impl From<PreloadProg> for TaskSummary {
impl PreloadProg {
pub fn cooked(self) -> bool { self.state == Some(true) }
pub fn running(self) -> bool { self.state.is_none() }
pub fn running(self) -> bool { self.state.is_none() || (self.cleaned.is_none() && self.cooked()) }
pub fn success(self) -> bool { self.cooked() }
pub fn success(self) -> bool { self.cleaned == Some(true) && self.cooked() }
pub fn failed(self) -> bool { self.state == Some(false) }
pub fn failed(self) -> bool { self.cleaned == Some(false) || self.state == Some(false) }
pub fn cleaned(self) -> Option<bool> { None }
pub fn cleaned(self) -> Option<bool> { self.cleaned }
pub fn percent(self) -> Option<f32> { None }
}

View file

@ -11,9 +11,9 @@ pub struct ProcessProgBlock {
impl From<ProcessProgBlock> for TaskSummary {
fn from(value: ProcessProgBlock) -> Self {
Self {
total: (value.state == Some(false)) as u32,
total: value.failed() as u32,
success: 0,
failed: (value.state == Some(false)) as u32,
failed: value.failed() as u32,
percent: value.percent().map(Into::into),
}
}
@ -42,9 +42,9 @@ pub struct ProcessProgOrphan {
impl From<ProcessProgOrphan> for TaskSummary {
fn from(value: ProcessProgOrphan) -> Self {
Self {
total: (value.state == Some(false)) as u32,
total: value.failed() as u32,
success: 0,
failed: (value.state == Some(false)) as u32,
failed: value.failed() as u32,
percent: value.percent().map(Into::into),
}
}
@ -74,8 +74,8 @@ impl From<ProcessProgBg> for TaskSummary {
fn from(value: ProcessProgBg) -> Self {
Self {
total: 1,
success: (value.state == Some(true)) as u32,
failed: (value.state == Some(false)) as u32,
success: value.success() as u32,
failed: value.failed() as u32,
percent: value.percent().map(Into::into),
}
}

View file

@ -3,10 +3,11 @@ use std::{ops::Deref, sync::Arc, time::Duration};
use hashbrown::HashMap;
use tokio::task::JoinHandle;
use yazi_config::{YAZI, plugin::{Fetcher, Preloader}};
use yazi_fs::FsHash64;
use yazi_runner::entry::EntryJob;
use yazi_shared::{CompletionToken, Id, SStr, Throttle, data::{Data, DataKey}, url::{UrlBuf, UrlLike}};
use crate::{Behavior, HIGH, LOW, NORMAL, Task, TaskProg, Worker, fetch::{FetchIn, FetchProg}, file::{FileInCopy, FileInCut, FileInDelete, FileInDownload, FileInHardlink, FileInLink, FileInTrash, FileInUpload, FileOutCopy, FileOutCut, FileOutDownload, FileOutHardlink, FileOutUpload, FileProgCopy, FileProgCut, FileProgDelete, FileProgDownload, FileProgHardlink, FileProgLink, FileProgTrash, FileProgUpload}, hook::{HookIn, HookInDelete, HookInDownload, HookInTrash, HookInUpload}, plugin::{PluginInEntry, PluginProgEntry}, preload::{PreloadIn, PreloadProg}, process::{ProcessInBg, ProcessInBlock, ProcessInOrphan, ProcessOpt, ProcessProgBg, ProcessProgBlock, ProcessProgOrphan}, size::{SizeIn, SizeProg}};
use crate::{Behavior, HIGH, LOW, NORMAL, Task, TaskProg, Worker, fetch::{FetchIn, FetchProg}, file::{FileInCopy, FileInCut, FileInDelete, FileInDownload, FileInHardlink, FileInLink, FileInTrash, FileInUpload, FileOutCopy, FileOutCut, FileOutDownload, FileOutHardlink, FileOutUpload, FileProgCopy, FileProgCut, FileProgDelete, FileProgDownload, FileProgHardlink, FileProgLink, FileProgTrash, FileProgUpload}, hook::{HookIn, HookInDelete, HookInDownload, HookInPreload, HookInTrash, HookInUpload}, plugin::{PluginInEntry, PluginProgEntry}, preload::{PreloadIn, PreloadProg}, process::{ProcessInBg, ProcessInBlock, ProcessInOrphan, ProcessOpt, ProcessProgBg, ProcessProgBlock, ProcessProgOrphan}, size::{SizeIn, SizeProg}};
pub struct Scheduler {
pub worker: Worker,
@ -202,9 +203,14 @@ impl Scheduler {
pub fn preload_paged(&self, preloader: &'static Preloader, target: &yazi_fs::File) {
let name = format!("Run preloader `{}`", preloader.run.name);
let (id, done) = self.add::<PreloadProg, _>(name, |t| (t.id, t.done.clone()));
let hook = HookInPreload::new(preloader.idx, target.hash_u64());
self.preload.submit(PreloadIn { id, plugin: preloader, target: target.clone(), done });
let id = self.add_hooked::<PreloadProg, _>(name, hook, |t| t.id);
if let Some(prev) = self.preload.loading.lock().put(target.url.hash_u64(), id) {
self.cancel(prev);
}
self.preload.submit(PreloadIn { id, plugin: preloader, target: target.clone() });
}
pub fn prework_size(&self, targets: Vec<&UrlBuf>) {

View file

@ -30,20 +30,18 @@ impl Worker {
let (process_tx, process_rx) = async_priority_channel::unbounded();
let (hook_tx, hook_rx) = async_priority_channel::unbounded();
let (op_tx, op_rx) = mpsc::unbounded_channel();
let ongoing = Arc::new(Mutex::new(Ongoing::default()));
let file = Arc::new(File::new(&op_tx, file_tx));
let plugin = Arc::new(Plugin::new(&op_tx, plugin_tx));
let fetch = Arc::new(Fetch::new(&op_tx, fetch_tx));
let preload = Arc::new(Preload::new(&op_tx, preload_tx));
let size = Arc::new(Size::new(&op_tx, size_tx));
let process = Arc::new(Process::new(&op_tx, process_tx));
let hook = Arc::new(Hook::new(&op_tx, &ongoing, &preload, hook_tx));
let me = Self {
file: Arc::new(File::new(&op_tx, file_tx)),
plugin: Arc::new(Plugin::new(&op_tx, plugin_tx)),
fetch: Arc::new(Fetch::new(&op_tx, fetch_tx)),
preload: Arc::new(Preload::new(&op_tx, preload_tx)),
size: Arc::new(Size::new(&op_tx, size_tx)),
process: Arc::new(Process::new(&op_tx, process_tx)),
hook: Arc::new(Hook::new(&op_tx, &ongoing, hook_tx)),
ops: TaskOps(op_tx),
ongoing,
};
let me =
Self { file, plugin, fetch, preload, size, process, hook, ops: TaskOps(op_tx), ongoing };
let handles = []
.into_iter()
@ -270,6 +268,7 @@ impl Worker {
HookIn::Hardlink(r#in) => self.hook.hardlink(r#in).await,
HookIn::Download(r#in) => self.hook.download(r#in).await,
HookIn::Upload(r#in) => self.hook.upload(r#in).await,
HookIn::Preload(r#in) => self.hook.preload(r#in).await,
}
}