This commit is contained in:
sxyazi 2023-11-29 01:29:53 +08:00
parent 66a3e7efaa
commit bdc518a0bb
No known key found for this signature in database
20 changed files with 141 additions and 156 deletions

13
Cargo.lock generated
View file

@ -2554,7 +2554,6 @@ name = "yazi-core"
version = "0.1.5"
dependencies = [
"anyhow",
"async-channel",
"bitflags 2.4.1",
"clipboard-win",
"crossterm",
@ -2566,12 +2565,10 @@ dependencies = [
"ratatui",
"regex",
"serde",
"serde_json",
"syntect",
"tokio",
"tokio-stream",
"tracing",
"trash",
"unicode-width",
"yazi-adaptor",
"yazi-config",
@ -2632,27 +2629,17 @@ version = "0.1.5"
dependencies = [
"anyhow",
"async-channel",
"bitflags 2.4.1",
"clipboard-win",
"crossterm",
"futures",
"indexmap",
"libc",
"notify",
"parking_lot",
"ratatui",
"regex",
"serde",
"serde_json",
"syntect",
"tokio",
"tokio-stream",
"tracing",
"trash",
"unicode-width",
"yazi-adaptor",
"yazi-config",
"yazi-prebuild",
"yazi-shared",
]

View file

@ -15,25 +15,22 @@ yazi-scheduler = { path = "../yazi-scheduler", version = "0.1.5" }
yazi-shared = { path = "../yazi-shared", version = "0.1.5" }
# External dependencies
anyhow = "^1"
async-channel = "^1"
bitflags = "^2"
crossterm = "^0"
futures = "^0"
indexmap = "^2"
libc = "^0"
notify = { version = "^6", default-features = false, features = [ "macos_fsevent" ] }
parking_lot = "^0"
ratatui = "^0"
regex = "^1"
serde = "^1"
serde_json = "^1"
syntect = { version = "^5", default-features = false, features = [ "parsing", "default-themes", "plist-load", "regex-onig" ] }
tokio = { version = "^1", features = [ "parking_lot", "macros", "rt-multi-thread", "sync", "time", "fs", "process", "io-std", "io-util" ] }
tokio-stream = "^0"
trash = "^3"
unicode-width = "^0"
yazi-prebuild = "^0"
anyhow = "^1"
bitflags = "^2"
crossterm = "^0"
futures = "^0"
indexmap = "^2"
libc = "^0"
notify = { version = "^6", default-features = false, features = [ "macos_fsevent" ] }
parking_lot = "^0"
ratatui = "^0"
regex = "^1"
serde = "^1"
syntect = { version = "^5", default-features = false, features = [ "parsing", "default-themes", "plist-load", "regex-onig" ] }
tokio = { version = "^1", features = [ "parking_lot", "macros", "rt-multi-thread", "sync", "time", "fs", "process", "io-std", "io-util" ] }
tokio-stream = "^0"
unicode-width = "^0"
yazi-prebuild = "^0"
# Logging
tracing = { version = "^0", features = [ "max_level_debug", "release_max_level_warn" ] }

View file

@ -1,7 +1,5 @@
use ratatui::prelude::Rect;
use tokio::sync::oneshot;
use yazi_config::popup::{Origin, Position};
use yazi_shared::{emit, event::Exec, Layer};
use crate::{completion::Completion, help::Help, input::Input, manager::Manager, select::Select, tasks::Tasks, which::Which};
@ -29,19 +27,10 @@ impl Ctx {
}
#[inline]
pub async fn stop() {
let (tx, rx) = oneshot::channel::<()>();
emit!(Call(Exec::call("stop", vec!["true".to_string()]).with_data(Some(tx)).vec(), Layer::App));
rx.await.ok();
}
pub async fn stop() { yazi_scheduler::Scheduler::app_stop().await }
#[inline]
pub fn resume() {
emit!(Call(
Exec::call("stop", vec!["false".to_string()]).with_data(None::<oneshot::Sender<()>>).vec(),
Layer::App
));
}
pub fn resume() { yazi_scheduler::Scheduler::app_resume() }
pub fn area(&self, position: &Position) -> Rect {
if position.origin != Origin::Hovered {

View file

@ -6,7 +6,6 @@
clippy::unit_arg
)]
mod blocker;
pub mod completion;
mod context;
pub mod files;
@ -21,9 +20,8 @@ pub mod tab;
pub mod tasks;
pub mod which;
pub use blocker::*;
pub use context::*;
pub use highlighter::*;
pub use step::*;
pub fn init() { init_blocker(); }
pub fn init() { yazi_scheduler::init(); }

View file

@ -3,10 +3,10 @@ use std::{collections::BTreeMap, ffi::OsStr, io::{stdout, BufWriter, Write}, pat
use anyhow::{anyhow, bail, Result};
use tokio::{fs::{self, OpenOptions}, io::{stdin, AsyncReadExt, AsyncWriteExt}};
use yazi_config::{popup::InputCfg, OPEN, PREVIEW};
use yazi_scheduler::external::{self, ShellOpt};
use yazi_scheduler::{external::{self, ShellOpt}, BLOCKER};
use yazi_shared::{emit, event::Exec, fs::{max_common_root, File, FilesOp, Url}, term::Term, Defer};
use crate::{input::Input, manager::Manager, Ctx, BLOCKER};
use crate::{input::Input, manager::Manager, Ctx};
pub struct Opt {
force: bool,

View file

@ -1,7 +1,7 @@
use yazi_scheduler::external::{self, FzfOpt, ZoxideOpt};
use yazi_scheduler::{external::{self, FzfOpt, ZoxideOpt}, BLOCKER};
use yazi_shared::{event::Exec, fs::ends_with_slash, Defer};
use crate::{tab::Tab, Ctx, BLOCKER};
use crate::{tab::Tab, Ctx};
pub struct Opt {
type_: OptType,

View file

@ -2,9 +2,10 @@ use std::io::{stdout, Write};
use crossterm::terminal::{disable_raw_mode, enable_raw_mode};
use tokio::{io::{stdin, AsyncReadExt}, select, sync::mpsc, time};
use yazi_scheduler::BLOCKER;
use yazi_shared::{event::Exec, term::Term, Defer};
use crate::{tasks::Tasks, Ctx, BLOCKER};
use crate::{tasks::Tasks, Ctx};
pub struct Opt;

View file

@ -1,13 +1,8 @@
mod commands;
mod running;
mod scheduler;
mod task;
mod progress;
mod tasks;
mod workers;
use running::*;
use scheduler::*;
use task::*;
pub use progress::*;
pub use tasks::*;
pub const TASKS_PADDING: u16 = 2;

View file

@ -0,0 +1,31 @@
use serde::Serialize;
use yazi_scheduler::Running;
#[derive(Clone, Copy, Default, Eq, PartialEq, Serialize)]
pub struct TasksProgress {
pub total: u32,
pub succ: u32,
pub fail: u32,
pub found: u64,
pub processed: u64,
}
impl From<&Running> for TasksProgress {
fn from(running: &Running) -> Self {
let mut progress = Self::default();
if running.is_empty() {
return progress;
}
for task in running.values() {
progress.total += task.total;
progress.succ += task.succ;
progress.fail += task.fail;
progress.found += task.found;
progress.processed += task.processed;
}
progress
}
}

View file

@ -1,11 +1,12 @@
use std::{collections::{BTreeMap, HashMap, HashSet}, ffi::OsStr, path::Path, sync::Arc};
use std::{collections::{BTreeMap, HashMap, HashSet}, ffi::OsStr, path::Path, sync::Arc, time::Duration};
use serde::Serialize;
use tokio::time::sleep;
use tracing::debug;
use yazi_config::{manager::SortBy, open::Opener, popup::InputCfg, OPEN};
use yazi_shared::{fs::File, fs::Url, term::Term, MimeKind};
use yazi_scheduler::{Scheduler, TaskSummary};
use yazi_shared::{fs::{File, Url}, term::Term, MimeKind};
use super::{running::Running, task::TaskSummary, Scheduler, TASKS_PADDING, TASKS_PERCENT};
use super::{TasksProgress, TASKS_PADDING, TASKS_PERCENT};
use crate::{files::Files, input::Input};
pub struct Tasks {
@ -18,12 +19,28 @@ pub struct Tasks {
impl Tasks {
pub fn start() -> Self {
Self {
let tasks = Self {
scheduler: Arc::new(Scheduler::start()),
visible: false,
cursor: 0,
progress: Default::default(),
}
};
let running = tasks.scheduler.running.clone();
tokio::spawn(async move {
let mut last = TasksProgress::default();
loop {
sleep(Duration::from_millis(500)).await;
let new = TasksProgress::from(&*running.read());
if last != new {
last = new;
Tasks::_update(new);
}
}
});
tasks
}
#[inline]
@ -209,32 +226,3 @@ impl Tasks {
#[inline]
pub fn len(&self) -> usize { self.scheduler.running.read().len() }
}
#[derive(Clone, Copy, Default, Eq, PartialEq, Serialize)]
pub struct TasksProgress {
pub total: u32,
pub succ: u32,
pub fail: u32,
pub found: u64,
pub processed: u64,
}
impl From<&Running> for TasksProgress {
fn from(running: &Running) -> Self {
let mut progress = Self::default();
if running.is_empty() {
return progress;
}
for task in running.values() {
progress.total += task.total;
progress.succ += task.succ;
progress.fail += task.fail;
progress.found += task.found;
progress.processed += task.processed;
}
progress
}
}

View file

@ -16,26 +16,14 @@ yazi-shared = { path = "../yazi-shared", version = "0.1.5" }
# External dependencies
anyhow = "^1"
async-channel = "^1"
bitflags = "^2"
crossterm = "^0"
futures = "^0"
indexmap = "^2"
libc = "^0"
notify = { version = "^6", default-features = false, features = [ "macos_fsevent" ] }
parking_lot = "^0"
ratatui = "^0"
regex = "^1"
serde = "^1"
serde_json = "^1"
syntect = { version = "^5", default-features = false, features = [ "parsing", "default-themes", "plist-load", "regex-onig" ] }
tokio = { version = "^1", features = [ "parking_lot", "macros", "rt-multi-thread", "sync", "time", "fs", "process", "io-std", "io-util" ] }
tokio-stream = "^0"
tokio = { version = "^1", features = [ "parking_lot", "rt-multi-thread" ] }
trash = "^3"
unicode-width = "^0"
yazi-prebuild = "^0"
# Logging
tracing = { version = "^0", features = [ "max_level_debug", "release_max_level_warn" ] }
[target."cfg(windows)".dependencies]
clipboard-win = "^4"

View file

@ -1 +1,15 @@
#![allow(clippy::unit_arg)]
mod blocker;
pub mod external;
mod running;
mod scheduler;
mod task;
pub mod workers;
pub use blocker::*;
pub use running::*;
pub use scheduler::*;
pub use task::*;
pub fn init() { init_blocker(); }

View file

@ -5,7 +5,7 @@ use futures::future::BoxFuture;
use super::{Task, TaskStage};
#[derive(Default)]
pub(super) struct Running {
pub struct Running {
incr: usize,
pub(super) hooks:
@ -21,25 +21,25 @@ impl Running {
}
#[inline]
pub(super) fn get(&self, id: usize) -> Option<&Task> { self.all.get(&id) }
pub fn get(&self, id: usize) -> Option<&Task> { self.all.get(&id) }
#[inline]
pub(super) fn get_mut(&mut self, id: usize) -> Option<&mut Task> { self.all.get_mut(&id) }
pub fn get_mut(&mut self, id: usize) -> Option<&mut Task> { self.all.get_mut(&id) }
#[inline]
pub(super) fn get_id(&self, idx: usize) -> Option<usize> { self.values().nth(idx).map(|t| t.id) }
pub fn get_id(&self, idx: usize) -> Option<usize> { self.values().nth(idx).map(|t| t.id) }
#[inline]
pub(super) fn len(&self) -> usize { self.all.len() }
pub fn len(&self) -> usize { self.all.len() }
#[inline]
pub(super) fn exists(&self, id: usize) -> bool { self.all.contains_key(&id) }
#[inline]
pub(super) fn values(&self) -> impl Iterator<Item = &Task> { self.all.values() }
pub fn values(&self) -> impl Iterator<Item = &Task> { self.all.values() }
#[inline]
pub(super) fn is_empty(&self) -> bool { self.all.is_empty() }
pub fn is_empty(&self) -> bool { self.all.is_empty() }
pub(super) fn try_remove(
&mut self,

View file

@ -2,25 +2,25 @@ use std::{ffi::OsStr, sync::Arc, time::Duration};
use futures::{future::BoxFuture, FutureExt};
use parking_lot::RwLock;
use tokio::{fs, select, sync::{mpsc::{self, UnboundedReceiver}, oneshot}, time::sleep};
use tokio::{fs, select, sync::{mpsc::{self, UnboundedReceiver}, oneshot}};
use yazi_config::{open::Opener, TASKS};
use yazi_shared::{fs::{unique_path, Url}, Throttle};
use yazi_shared::{emit, event::Exec, fs::{unique_path, Url}, Layer, Throttle};
use super::{workers::{File, FileOpDelete, FileOpLink, FileOpPaste, FileOpTrash, Precache, PrecacheOpMime, PrecacheOpSize, Process, ProcessOpOpen}, Running, TaskOp, TaskStage, TasksProgress};
use crate::tasks::Tasks;
use super::{Running, TaskOp, TaskStage};
use crate::workers::{File, FileOpDelete, FileOpLink, FileOpPaste, FileOpTrash, Precache, PrecacheOpMime, PrecacheOpSize, Process, ProcessOpOpen};
pub struct Scheduler {
file: Arc<File>,
precache: Arc<Precache>,
process: Arc<Process>,
todo: async_channel::Sender<BoxFuture<'static, ()>>,
prog: mpsc::UnboundedSender<TaskOp>,
pub(super) running: Arc<RwLock<Running>>,
todo: async_channel::Sender<BoxFuture<'static, ()>>,
prog: mpsc::UnboundedSender<TaskOp>,
pub running: Arc<RwLock<Running>>,
}
impl Scheduler {
pub(super) fn start() -> Self {
pub fn start() -> Self {
let (todo_tx, todo_rx) = async_channel::unbounded();
let (prog_tx, prog_rx) = mpsc::unbounded_channel();
@ -147,23 +147,9 @@ impl Scheduler {
}
}
});
let running = self.running.clone();
tokio::spawn(async move {
let mut last = TasksProgress::default();
loop {
sleep(Duration::from_millis(500)).await;
let new = TasksProgress::from(&*running.read());
if last != new {
last = new;
Tasks::_update(new);
}
}
});
}
pub(super) fn cancel(&self, id: usize) -> bool {
pub fn cancel(&self, id: usize) -> bool {
let mut running = self.running.write();
let b = running.all.remove(&id).is_some();
@ -173,7 +159,20 @@ impl Scheduler {
b
}
pub(super) fn file_cut(&self, from: Url, mut to: Url, force: bool) {
pub async fn app_stop() {
let (tx, rx) = oneshot::channel::<()>();
emit!(Call(Exec::call("stop", vec!["true".to_string()]).with_data(Some(tx)).vec(), Layer::App));
rx.await.ok();
}
pub fn app_resume() {
emit!(Call(
Exec::call("stop", vec!["false".to_string()]).with_data(None::<oneshot::Sender<()>>).vec(),
Layer::App
));
}
pub fn file_cut(&self, from: Url, mut to: Url, force: bool) {
let mut running = self.running.write();
let id = running.add(format!("Cut {:?} to {:?}", from, to));
@ -204,7 +203,7 @@ impl Scheduler {
});
}
pub(super) fn file_copy(&self, from: Url, mut to: Url, force: bool) {
pub fn file_copy(&self, from: Url, mut to: Url, force: bool) {
let name = format!("Copy {:?} to {:?}", from, to);
let id = self.running.write().add(name);
@ -220,7 +219,7 @@ impl Scheduler {
});
}
pub(super) fn file_link(&self, from: Url, mut to: Url, relative: bool, force: bool) {
pub fn file_link(&self, from: Url, mut to: Url, relative: bool, force: bool) {
let name = format!("Link {from:?} to {to:?}");
let id = self.running.write().add(name);
@ -239,7 +238,7 @@ impl Scheduler {
});
}
pub(super) fn file_delete(&self, target: Url) {
pub fn file_delete(&self, target: Url) {
let mut running = self.running.write();
let id = running.add(format!("Delete {:?}", target));
@ -267,7 +266,7 @@ impl Scheduler {
});
}
pub(super) fn file_trash(&self, target: Url) {
pub fn file_trash(&self, target: Url) {
let name = format!("Trash {:?}", target);
let id = self.running.write().add(name);
@ -280,7 +279,7 @@ impl Scheduler {
});
}
pub(super) fn process_open(&self, opener: &Opener, args: &[impl AsRef<OsStr>]) {
pub fn process_open(&self, opener: &Opener, args: &[impl AsRef<OsStr>]) {
let name = {
let s = format!("Execute `{}`", opener.exec);
let args = args.iter().map(|a| a.as_ref().to_string_lossy()).collect::<Vec<_>>().join(" ");
@ -324,7 +323,7 @@ impl Scheduler {
});
}
pub(super) fn precache_size(&self, targets: Vec<&Url>) {
pub fn precache_size(&self, targets: Vec<&Url>) {
let throttle = Arc::new(Throttle::new(targets.len(), Duration::from_millis(300)));
let mut handing = self.precache.size_handing.lock();
let mut running = self.running.write();
@ -349,7 +348,7 @@ impl Scheduler {
}
}
pub(super) fn precache_mime(&self, targets: Vec<Url>) {
pub fn precache_mime(&self, targets: Vec<Url>) {
let name = format!("Preload mimetype for {} files", targets.len());
let id = self.running.write().add(name);
@ -362,21 +361,21 @@ impl Scheduler {
});
}
pub(super) fn precache_image(&self, targets: Vec<Url>) {
pub fn precache_image(&self, targets: Vec<Url>) {
let name = format!("Precache of {} image files", targets.len());
let id = self.running.write().add(name);
self.precache.image(id, targets).ok();
}
pub(super) fn precache_video(&self, targets: Vec<Url>) {
pub fn precache_video(&self, targets: Vec<Url>) {
let name = format!("Precache of {} video files", targets.len());
let id = self.running.write().add(name);
self.precache.video(id, targets).ok();
}
pub(super) fn precache_pdf(&self, targets: Vec<Url>) {
pub fn precache_pdf(&self, targets: Vec<Url>) {
let name = format!("Precache of {} PDF files", targets.len());
let id = self.running.write().add(name);

View file

@ -7,7 +7,7 @@ use tracing::warn;
use yazi_config::TASKS;
use yazi_shared::fs::{calculate_size, copy_with_progress, path_relative_to, Url};
use crate::tasks::TaskOp;
use crate::TaskOp;
pub(crate) struct File {
tx: async_channel::Sender<FileOp>,

View file

@ -5,10 +5,9 @@ use parking_lot::Mutex;
use tokio::{fs, sync::mpsc};
use yazi_adaptor::Image;
use yazi_config::PREVIEW;
use yazi_scheduler::external;
use yazi_shared::{emit, fs::{calculate_size, FilesOp, Url}, Throttle};
use crate::tasks::TaskOp;
use crate::{external, TaskOp};
pub(crate) struct Precache {
tx: async_channel::Sender<PrecacheOp>,

View file

@ -2,9 +2,8 @@ use std::{ffi::OsString, mem};
use anyhow::Result;
use tokio::{io::{AsyncBufReadExt, BufReader}, select, sync::{mpsc, oneshot}};
use yazi_scheduler::external::{self, ShellOpt};
use crate::{tasks::TaskOp, Ctx, BLOCKER};
use crate::{external::{self, ShellOpt}, Scheduler, TaskOp, BLOCKER};
pub(crate) struct Process {
sch: mpsc::UnboundedSender<TaskOp>,
@ -38,7 +37,7 @@ impl Process {
let opt = ShellOpt::from(&mut task);
if task.block {
let _guard = BLOCKER.acquire().await.unwrap();
Ctx::stop().await;
Scheduler::app_stop().await;
match external::shell(opt) {
Ok(mut child) => {
@ -50,7 +49,7 @@ impl Process {
self.fail(task.id, format!("Failed to spawn process: {e}"))?;
}
}
return Ok(Ctx::resume());
return Ok(Scheduler::app_resume());
}
if task.orphan {