diff --git a/yazi-core/src/tasks/file.rs b/yazi-core/src/tasks/file.rs new file mode 100644 index 00000000..7e2e2fe3 --- /dev/null +++ b/yazi-core/src/tasks/file.rs @@ -0,0 +1,51 @@ +use std::collections::HashSet; + +use tracing::debug; +use yazi_shared::fs::Url; + +use super::Tasks; + +impl Tasks { + pub fn file_cut(&self, src: &[&Url], dest: &Url, force: bool) { + for &u in src { + let to = dest.join(u.file_name().unwrap()); + if force && *u == to { + debug!("file_cut: same file, skipping {:?}", to); + } else { + self.scheduler.file_cut(u.clone(), to, force); + } + } + } + + pub fn file_copy(&self, src: &[&Url], dest: &Url, force: bool, follow: bool) { + for &u in src { + let to = dest.join(u.file_name().unwrap()); + if force && *u == to { + debug!("file_copy: same file, skipping {:?}", to); + } else { + self.scheduler.file_copy(u.clone(), to, force, follow); + } + } + } + + pub fn file_link(&self, src: &HashSet, dest: &Url, relative: bool, force: bool) { + for u in src { + let to = dest.join(u.file_name().unwrap()); + if force && *u == to { + debug!("file_link: same file, skipping {:?}", to); + } else { + self.scheduler.file_link(u.clone(), to, relative, force); + } + } + } + + pub fn file_remove(&self, targets: Vec, permanently: bool) { + for u in targets { + if permanently { + self.scheduler.file_delete(u); + } else { + self.scheduler.file_trash(u); + } + } + } +} diff --git a/yazi-core/src/tasks/mod.rs b/yazi-core/src/tasks/mod.rs index df6e5caa..32abaac5 100644 --- a/yazi-core/src/tasks/mod.rs +++ b/yazi-core/src/tasks/mod.rs @@ -1,4 +1,7 @@ mod commands; +mod file; +mod plugin; +mod preload; mod process; mod progress; mod tasks; diff --git a/yazi-core/src/tasks/plugin.rs b/yazi-core/src/tasks/plugin.rs new file mode 100644 index 00000000..665dddda --- /dev/null +++ b/yazi-core/src/tasks/plugin.rs @@ -0,0 +1,15 @@ +use yazi_plugin::ValueSendable; + +use super::Tasks; + +impl Tasks { + #[inline] + pub fn plugin_micro(&self, name: String, args: Vec) { + self.scheduler.plugin_micro(name, args); + } + + #[inline] + pub fn plugin_macro(&self, name: String, args: Vec) { + self.scheduler.plugin_macro(name, args); + } +} diff --git a/yazi-core/src/tasks/preload.rs b/yazi-core/src/tasks/preload.rs new file mode 100644 index 00000000..8f1915df --- /dev/null +++ b/yazi-core/src/tasks/preload.rs @@ -0,0 +1,94 @@ +use std::{collections::HashMap, mem}; + +use yazi_config::{manager::SortBy, plugin::{PluginRule, MAX_PRELOADERS}, PLUGIN}; +use yazi_shared::{fs::{File, Url}, MIME_DIR}; + +use super::Tasks; +use crate::folder::Files; + +impl Tasks { + pub fn preload_paged(&self, paged: &[File], mimetype: &HashMap) { + let mut single_tasks = Vec::with_capacity(paged.len()); + let mut multi_tasks: [Vec<_>; MAX_PRELOADERS as usize] = Default::default(); + + let loaded = self.scheduler.preload.rule_loaded.read(); + for f in paged { + let mime = if f.is_dir() { Some(MIME_DIR) } else { mimetype.get(&f.url).map(|s| &**s) }; + let factors = |s: &str| match s { + "mime" => mime.is_some(), + _ => false, + }; + + for rule in PLUGIN.preloaders(&f.url, mime, factors) { + if loaded.get(&f.url).is_some_and(|x| x & (1 << rule.id) != 0) { + continue; + } + if rule.multi { + multi_tasks[rule.id as usize].push(f); + } else { + single_tasks.push((rule, f)); + } + } + } + + drop(loaded); + let mut loaded = self.scheduler.preload.rule_loaded.write(); + + let mut go = |rule: &PluginRule, targets: Vec<&File>| { + for &f in &targets { + if let Some(n) = loaded.get_mut(&f.url) { + *n |= 1 << rule.id; + } else { + loaded.insert(f.url.clone(), 1 << rule.id); + } + } + self.scheduler.preload_paged(rule, targets); + }; + + #[allow(clippy::needless_range_loop)] + for i in 0..PLUGIN.preloaders.len() { + if !multi_tasks[i].is_empty() { + go(&PLUGIN.preloaders[i], mem::take(&mut multi_tasks[i])); + } + } + for (rule, target) in single_tasks { + go(rule, vec![target]); + } + } + + pub fn preload_affected(&self, affected: &[File], mimetype: &HashMap) { + { + let mut loaded = self.scheduler.preload.rule_loaded.write(); + for f in affected { + loaded.remove(&f.url); + } + } + + self.preload_paged(affected, mimetype); + } + + pub fn preload_sorted(&self, targets: &Files) { + if targets.sorter().by != SortBy::Size { + return; + } + + let targets: Vec<_> = { + let loading = self.scheduler.preload.size_loading.read(); + targets + .iter() + .filter(|f| f.is_dir() && !targets.sizes.contains_key(&f.url) && !loading.contains(&f.url)) + .map(|f| &f.url) + .collect() + }; + if targets.is_empty() { + return; + } + + let mut loading = self.scheduler.preload.size_loading.write(); + for &target in &targets { + loading.insert(target.clone()); + } + + self.scheduler.preload_size(targets); + } +} diff --git a/yazi-core/src/tasks/tasks.rs b/yazi-core/src/tasks/tasks.rs index d84138cd..69b01178 100644 --- a/yazi-core/src/tasks/tasks.rs +++ b/yazi-core/src/tasks/tasks.rs @@ -1,14 +1,10 @@ -use std::{collections::{HashMap, HashSet}, mem, sync::Arc, time::Duration}; +use std::{sync::Arc, time::Duration}; use tokio::time::sleep; -use tracing::debug; -use yazi_config::{manager::SortBy, plugin::{PluginRule, MAX_PRELOADERS}, PLUGIN}; -use yazi_plugin::ValueSendable; use yazi_scheduler::{Scheduler, TaskSummary}; -use yazi_shared::{emit, event::Cmd, fs::{File, Url}, term::Term, Layer, MIME_DIR}; +use yazi_shared::{emit, event::Cmd, term::Term, Layer}; use super::{TasksProgress, TASKS_BORDER, TASKS_PADDING, TASKS_PERCENT}; -use crate::folder::Files; pub struct Tasks { pub(super) scheduler: Arc, @@ -56,146 +52,6 @@ impl Tasks { ongoing.values().take(Self::limit()).map(Into::into).collect() } - pub fn file_cut(&self, src: &[&Url], dest: &Url, force: bool) { - for &u in src { - let to = dest.join(u.file_name().unwrap()); - if force && *u == to { - debug!("file_cut: same file, skipping {:?}", to); - } else { - self.scheduler.file_cut(u.clone(), to, force); - } - } - } - - pub fn file_copy(&self, src: &[&Url], dest: &Url, force: bool, follow: bool) { - for &u in src { - let to = dest.join(u.file_name().unwrap()); - if force && *u == to { - debug!("file_copy: same file, skipping {:?}", to); - } else { - self.scheduler.file_copy(u.clone(), to, force, follow); - } - } - } - - pub fn file_link(&self, src: &HashSet, dest: &Url, relative: bool, force: bool) { - for u in src { - let to = dest.join(u.file_name().unwrap()); - if force && *u == to { - debug!("file_link: same file, skipping {:?}", to); - } else { - self.scheduler.file_link(u.clone(), to, relative, force); - } - } - } - - pub fn file_remove(&self, targets: Vec, permanently: bool) { - for u in targets { - if permanently { - self.scheduler.file_delete(u); - } else { - self.scheduler.file_trash(u); - } - } - } - - #[inline] - pub fn plugin_micro(&self, name: String, args: Vec) { - self.scheduler.plugin_micro(name, args); - } - - #[inline] - pub fn plugin_macro(&self, name: String, args: Vec) { - self.scheduler.plugin_macro(name, args); - } - - pub fn preload_paged(&self, paged: &[File], mimetype: &HashMap) { - let mut single_tasks = Vec::with_capacity(paged.len()); - let mut multi_tasks: [Vec<_>; MAX_PRELOADERS as usize] = Default::default(); - - let loaded = self.scheduler.preload.rule_loaded.read(); - for f in paged { - let mime = if f.is_dir() { Some(MIME_DIR) } else { mimetype.get(&f.url).map(|s| &**s) }; - let factors = |s: &str| match s { - "mime" => mime.is_some(), - _ => false, - }; - - for rule in PLUGIN.preloaders(&f.url, mime, factors) { - if loaded.get(&f.url).is_some_and(|x| x & (1 << rule.id) != 0) { - continue; - } - if rule.multi { - multi_tasks[rule.id as usize].push(f); - } else { - single_tasks.push((rule, f)); - } - } - } - - drop(loaded); - let mut loaded = self.scheduler.preload.rule_loaded.write(); - - let mut go = |rule: &PluginRule, targets: Vec<&File>| { - for &f in &targets { - if let Some(n) = loaded.get_mut(&f.url) { - *n |= 1 << rule.id; - } else { - loaded.insert(f.url.clone(), 1 << rule.id); - } - } - self.scheduler.preload_paged(rule, targets); - }; - - #[allow(clippy::needless_range_loop)] - for i in 0..PLUGIN.preloaders.len() { - if !multi_tasks[i].is_empty() { - go(&PLUGIN.preloaders[i], mem::take(&mut multi_tasks[i])); - } - } - for (rule, target) in single_tasks { - go(rule, vec![target]); - } - } - - pub fn preload_affected(&self, affected: &[File], mimetype: &HashMap) { - { - let mut loaded = self.scheduler.preload.rule_loaded.write(); - for f in affected { - loaded.remove(&f.url); - } - } - - self.preload_paged(affected, mimetype); - } - - pub fn preload_sorted(&self, targets: &Files) { - if targets.sorter().by != SortBy::Size { - return; - } - - let targets: Vec<_> = { - let loading = self.scheduler.preload.size_loading.read(); - targets - .iter() - .filter(|f| f.is_dir() && !targets.sizes.contains_key(&f.url) && !loading.contains(&f.url)) - .map(|f| &f.url) - .collect() - }; - if targets.is_empty() { - return; - } - - let mut loading = self.scheduler.preload.size_loading.write(); - for &target in &targets { - loading.insert(target.clone()); - } - - self.scheduler.preload_size(targets); - } -} - -impl Tasks { #[inline] pub fn len(&self) -> usize { self.scheduler.ongoing.lock().len() } }