mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
refactor: unify progress representation and add cleanup state (#3853)
This commit is contained in:
parent
4bb4f37555
commit
ec178fdb52
19 changed files with 663 additions and 661 deletions
692
Cargo.lock
generated
692
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -37,7 +37,7 @@ debug = false
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
ansi-to-tui = "8.0.1"
|
ansi-to-tui = "8.0.1"
|
||||||
anyhow = "1.0.102"
|
anyhow = "1.0.102"
|
||||||
arc-swap = "1.9.0"
|
arc-swap = "1.9.1"
|
||||||
base64 = "0.22.1"
|
base64 = "0.22.1"
|
||||||
bitflags = { version = "2.11.0", features = [ "serde" ] }
|
bitflags = { version = "2.11.0", features = [ "serde" ] }
|
||||||
chrono = "0.4.44"
|
chrono = "0.4.44"
|
||||||
|
|
@ -60,10 +60,10 @@ ordered-float = { version = "5.3.0", features = [ "serde" ] }
|
||||||
parking_lot = "0.12.5"
|
parking_lot = "0.12.5"
|
||||||
paste = "1.0.15"
|
paste = "1.0.15"
|
||||||
percent-encoding = "2.3.2"
|
percent-encoding = "2.3.2"
|
||||||
rand = { version = "0.9.2", default-features = false, features = [ "os_rng", "small_rng", "std" ] }
|
rand = { version = "0.10.0", default-features = false, features = [ "std", "sys_rng" ] }
|
||||||
ratatui = { version = "0.30.0", features = [ "serde", "unstable-rendered-line-info", "unstable-widget-ref" ] }
|
ratatui = { version = "0.30.0", features = [ "serde", "unstable-rendered-line-info", "unstable-widget-ref" ] }
|
||||||
regex = "1.12.3"
|
regex = "1.12.3"
|
||||||
russh = { version = "0.59.0", default-features = false, features = [ "ring", "rsa" ] }
|
russh = { version = "0.60.0", default-features = false, features = [ "ring", "rsa" ] }
|
||||||
scopeguard = "1.2.0"
|
scopeguard = "1.2.0"
|
||||||
serde = { version = "1.0.228", features = [ "derive" ] }
|
serde = { version = "1.0.228", features = [ "derive" ] }
|
||||||
serde_json = "1.0.149"
|
serde_json = "1.0.149"
|
||||||
|
|
@ -71,7 +71,7 @@ serde_with = "3.18.0"
|
||||||
strum = { version = "0.28.0", features = [ "derive" ] }
|
strum = { version = "0.28.0", features = [ "derive" ] }
|
||||||
syntect = { version = "5.3.0", default-features = false, features = [ "parsing", "plist-load", "regex-onig" ] }
|
syntect = { version = "5.3.0", default-features = false, features = [ "parsing", "plist-load", "regex-onig" ] }
|
||||||
thiserror = "2.0.18"
|
thiserror = "2.0.18"
|
||||||
tokio = { version = "1.50.0", features = [ "full" ] }
|
tokio = { version = "1.51.0", features = [ "full" ] }
|
||||||
tokio-stream = "0.1.18"
|
tokio-stream = "0.1.18"
|
||||||
tokio-util = "0.7.18"
|
tokio-util = "0.7.18"
|
||||||
toml = { version = "1.1.2" }
|
toml = { version = "1.1.2" }
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ use std::ops::Deref;
|
||||||
|
|
||||||
use mlua::{AnyUserData, LuaSerdeExt, UserData, UserDataFields, Value};
|
use mlua::{AnyUserData, LuaSerdeExt, UserData, UserDataFields, Value};
|
||||||
use yazi_binding::{SER_OPT, cached_field};
|
use yazi_binding::{SER_OPT, cached_field};
|
||||||
|
use yazi_scheduler::Progress;
|
||||||
|
|
||||||
use super::{Lives, PtrCell};
|
use super::{Lives, PtrCell};
|
||||||
|
|
||||||
|
|
@ -29,8 +30,8 @@ impl UserData for TaskSnap {
|
||||||
cached_field!(fields, name, |lua, me| lua.create_string(&me.name));
|
cached_field!(fields, name, |lua, me| lua.create_string(&me.name));
|
||||||
cached_field!(fields, prog, |lua, me| lua.to_value_with(&me.prog, SER_OPT));
|
cached_field!(fields, prog, |lua, me| lua.to_value_with(&me.prog, SER_OPT));
|
||||||
|
|
||||||
fields.add_field_method_get("cooked", |_, me| Ok(me.prog.cooked()));
|
|
||||||
fields.add_field_method_get("running", |_, me| Ok(me.prog.running()));
|
fields.add_field_method_get("running", |_, me| Ok(me.prog.running()));
|
||||||
|
fields.add_field_method_get("cooked", |_, me| Ok(me.prog.cooked()));
|
||||||
fields.add_field_method_get("success", |_, me| Ok(me.prog.success()));
|
fields.add_field_method_get("success", |_, me| Ok(me.prog.success()));
|
||||||
fields.add_field_method_get("failed", |_, me| Ok(me.prog.failed()));
|
fields.add_field_method_get("failed", |_, me| Ok(me.prog.failed()));
|
||||||
fields.add_field_method_get("percent", |_, me| Ok(me.prog.percent()));
|
fields.add_field_method_get("percent", |_, me| Ok(me.prog.percent()));
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use rand::{RngCore, SeedableRng, rngs::SmallRng};
|
use rand::{Rng, make_rng, rngs::SmallRng};
|
||||||
use yazi_shared::{natsort, path::PathBufDyn, translit::Transliterator, url::UrlLike};
|
use yazi_shared::{natsort, path::PathBufDyn, translit::Transliterator, url::UrlLike};
|
||||||
|
|
||||||
use crate::{File, SortBy, SortFallback};
|
use crate::{File, SortBy, SortFallback};
|
||||||
|
|
@ -72,7 +72,7 @@ impl FilesSorter {
|
||||||
self.fallback(a, b, self.cmp(aa.unwrap_or(a.len), bb.unwrap_or(b.len)))
|
self.fallback(a, b, self.cmp(aa.unwrap_or(a.len), bb.unwrap_or(b.len)))
|
||||||
}),
|
}),
|
||||||
SortBy::Random => {
|
SortBy::Random => {
|
||||||
let mut rng = SmallRng::from_os_rng();
|
let mut rng = make_rng::<SmallRng>();
|
||||||
items.sort_unstable_by(|a, b| {
|
items.sort_unstable_by(|a, b| {
|
||||||
promote!(a, b);
|
promote!(a, b);
|
||||||
self.cmp(rng.next_u64(), rng.next_u64())
|
self.cmp(rng.next_u64(), rng.next_u64())
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ mlua = { workspace = true }
|
||||||
ordered-float = { workspace = true }
|
ordered-float = { workspace = true }
|
||||||
parking_lot = { workspace = true }
|
parking_lot = { workspace = true }
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
|
strum = { workspace = true }
|
||||||
tokio = { workspace = true }
|
tokio = { workspace = true }
|
||||||
tokio-util = { workspace = true }
|
tokio-util = { workspace = true }
|
||||||
tracing = { workspace = true }
|
tracing = { workspace = true }
|
||||||
|
|
|
||||||
11
yazi-scheduler/src/cleanup.rs
Normal file
11
yazi-scheduler/src/cleanup.rs
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
use serde::Serialize;
|
||||||
|
use strum::EnumIs;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Default, EnumIs, Eq, PartialEq, Serialize)]
|
||||||
|
#[serde(rename_all = "kebab-case")]
|
||||||
|
pub enum CleanupState {
|
||||||
|
#[default]
|
||||||
|
Pending,
|
||||||
|
Success,
|
||||||
|
Failed,
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::TaskSummary;
|
use crate::{Progress, TaskSummary};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize)]
|
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize)]
|
||||||
pub struct FetchProg {
|
pub struct FetchProg {
|
||||||
|
|
@ -18,16 +18,10 @@ impl From<FetchProg> for TaskSummary {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FetchProg {
|
impl Progress for FetchProg {
|
||||||
pub fn cooked(self) -> bool { self.state == Some(true) }
|
fn running(self) -> bool { self.state.is_none() }
|
||||||
|
|
||||||
pub fn running(self) -> bool { self.state.is_none() }
|
fn cooked(self) -> bool { self.state == Some(true) }
|
||||||
|
|
||||||
pub fn success(self) -> bool { self.cooked() }
|
fn failed(self) -> bool { self.state == Some(false) }
|
||||||
|
|
||||||
pub fn failed(self) -> bool { self.state == Some(false) }
|
|
||||||
|
|
||||||
pub fn cleaned(self) -> Option<bool> { None }
|
|
||||||
|
|
||||||
pub fn percent(self) -> Option<f32> { None }
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
use crate::{Task, TaskProg};
|
use crate::{CleanupState, Task, TaskProg};
|
||||||
|
|
||||||
// --- Copy
|
// --- Copy
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -41,7 +41,7 @@ impl FileOutCopy {
|
||||||
task.log(reason);
|
task.log(reason);
|
||||||
}
|
}
|
||||||
Self::Clean => {
|
Self::Clean => {
|
||||||
prog.cleaned = Some(true);
|
prog.cleaned = CleanupState::Success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -120,10 +120,10 @@ impl FileOutCut {
|
||||||
task.log(reason);
|
task.log(reason);
|
||||||
}
|
}
|
||||||
Self::Clean(Ok(())) => {
|
Self::Clean(Ok(())) => {
|
||||||
prog.cleaned = Some(true);
|
prog.cleaned = CleanupState::Success;
|
||||||
}
|
}
|
||||||
Self::Clean(Err(reason)) => {
|
Self::Clean(Err(reason)) => {
|
||||||
prog.cleaned = Some(false);
|
prog.cleaned = CleanupState::Failed;
|
||||||
task.log(format!("Failed cleaning up cut file: {reason:?}"));
|
task.log(format!("Failed cleaning up cut file: {reason:?}"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -188,7 +188,7 @@ impl FileOutLink {
|
||||||
task.log(reason);
|
task.log(reason);
|
||||||
}
|
}
|
||||||
Self::Clean => {
|
Self::Clean => {
|
||||||
prog.cleaned = Some(true);
|
prog.cleaned = CleanupState::Success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if let TaskProg::FileCopy(prog) = &mut task.prog {
|
} else if let TaskProg::FileCopy(prog) = &mut task.prog {
|
||||||
|
|
@ -255,7 +255,7 @@ impl FileOutHardlink {
|
||||||
task.log(reason);
|
task.log(reason);
|
||||||
}
|
}
|
||||||
Self::Clean => {
|
Self::Clean => {
|
||||||
prog.cleaned = Some(true);
|
prog.cleaned = CleanupState::Success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -316,10 +316,10 @@ impl FileOutDelete {
|
||||||
task.log(reason);
|
task.log(reason);
|
||||||
}
|
}
|
||||||
Self::Clean(Ok(())) => {
|
Self::Clean(Ok(())) => {
|
||||||
prog.cleaned = Some(true);
|
prog.cleaned = CleanupState::Success;
|
||||||
}
|
}
|
||||||
Self::Clean(Err(reason)) => {
|
Self::Clean(Err(reason)) => {
|
||||||
prog.cleaned = Some(false);
|
prog.cleaned = CleanupState::Failed;
|
||||||
task.log(format!("Failed cleaning up deleted file: {reason:?}"));
|
task.log(format!("Failed cleaning up deleted file: {reason:?}"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -377,7 +377,7 @@ impl FileOutTrash {
|
||||||
task.log(reason);
|
task.log(reason);
|
||||||
}
|
}
|
||||||
Self::Clean => {
|
Self::Clean => {
|
||||||
prog.cleaned = Some(true);
|
prog.cleaned = CleanupState::Success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -418,7 +418,7 @@ impl FileOutDownload {
|
||||||
task.log(reason);
|
task.log(reason);
|
||||||
}
|
}
|
||||||
Self::Clean => {
|
Self::Clean => {
|
||||||
prog.cleaned = Some(true);
|
prog.cleaned = CleanupState::Success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -493,7 +493,7 @@ impl FileOutUpload {
|
||||||
task.log(reason);
|
task.log(reason);
|
||||||
}
|
}
|
||||||
Self::Clean => {
|
Self::Clean => {
|
||||||
prog.cleaned = Some(true);
|
prog.cleaned = CleanupState::Success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::TaskSummary;
|
use crate::{CleanupState, Progress, TaskSummary};
|
||||||
|
|
||||||
// --- Copy
|
// --- Copy
|
||||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize)]
|
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize)]
|
||||||
|
|
@ -11,7 +11,7 @@ pub struct FileProgCopy {
|
||||||
pub total_bytes: u64,
|
pub total_bytes: u64,
|
||||||
pub processed_bytes: u64,
|
pub processed_bytes: u64,
|
||||||
pub collected: Option<bool>,
|
pub collected: Option<bool>,
|
||||||
pub cleaned: Option<bool>,
|
pub cleaned: CleanupState,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<FileProgCopy> for TaskSummary {
|
impl From<FileProgCopy> for TaskSummary {
|
||||||
|
|
@ -25,33 +25,21 @@ impl From<FileProgCopy> for TaskSummary {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FileProgCopy {
|
impl Progress for FileProgCopy {
|
||||||
pub fn cooked(self) -> bool {
|
fn running(self) -> bool {
|
||||||
self.collected == Some(true) && self.success_files == self.total_files
|
self.cooking_or_cleaning(
|
||||||
|
self.collected.is_none() || self.success_files + self.failed_files != self.total_files,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn running(self) -> bool {
|
fn cooked(self) -> bool { self.collected == Some(true) && self.success_files == self.total_files }
|
||||||
self.collected.is_none()
|
|
||||||
|| self.success_files + self.failed_files != self.total_files
|
|
||||||
|| (self.cleaned.is_none() && self.cooked())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn success(self) -> bool { self.cleaned == Some(true) && self.cooked() }
|
fn failed(self) -> bool { self.cleaned.is_failed() || self.collected == Some(false) }
|
||||||
|
|
||||||
pub fn failed(self) -> bool { self.cleaned == Some(false) || self.collected == Some(false) }
|
fn cleaned(self) -> Option<CleanupState> { Some(self.cleaned) }
|
||||||
|
|
||||||
pub fn cleaned(self) -> Option<bool> { self.cleaned }
|
fn percent(self) -> Option<f32> {
|
||||||
|
Some(self.byte_percent(self.processed_bytes, self.total_bytes))
|
||||||
pub fn percent(self) -> Option<f32> {
|
|
||||||
Some(if self.success() {
|
|
||||||
100.0
|
|
||||||
} else if self.failed() {
|
|
||||||
0.0
|
|
||||||
} else if self.total_bytes != 0 {
|
|
||||||
99.99f32.min(self.processed_bytes as f32 / self.total_bytes as f32 * 100.0)
|
|
||||||
} else {
|
|
||||||
99.99
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -64,7 +52,7 @@ pub struct FileProgCut {
|
||||||
pub total_bytes: u64,
|
pub total_bytes: u64,
|
||||||
pub processed_bytes: u64,
|
pub processed_bytes: u64,
|
||||||
pub collected: Option<bool>,
|
pub collected: Option<bool>,
|
||||||
pub cleaned: Option<bool>,
|
pub cleaned: CleanupState,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<FileProgCut> for TaskSummary {
|
impl From<FileProgCut> for TaskSummary {
|
||||||
|
|
@ -78,33 +66,21 @@ impl From<FileProgCut> for TaskSummary {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FileProgCut {
|
impl Progress for FileProgCut {
|
||||||
pub fn cooked(self) -> bool {
|
fn running(self) -> bool {
|
||||||
self.collected == Some(true) && self.success_files == self.total_files
|
self.cooking_or_cleaning(
|
||||||
|
self.collected.is_none() || self.success_files + self.failed_files != self.total_files,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn running(self) -> bool {
|
fn cooked(self) -> bool { self.collected == Some(true) && self.success_files == self.total_files }
|
||||||
self.collected.is_none()
|
|
||||||
|| self.success_files + self.failed_files != self.total_files
|
|
||||||
|| (self.cleaned.is_none() && self.cooked())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn success(self) -> bool { self.cleaned == Some(true) && self.cooked() }
|
fn failed(self) -> bool { self.cleaned.is_failed() || self.collected == Some(false) }
|
||||||
|
|
||||||
pub fn failed(self) -> bool { self.cleaned == Some(false) || self.collected == Some(false) }
|
fn cleaned(self) -> Option<CleanupState> { Some(self.cleaned) }
|
||||||
|
|
||||||
pub fn cleaned(self) -> Option<bool> { self.cleaned }
|
fn percent(self) -> Option<f32> {
|
||||||
|
Some(self.byte_percent(self.processed_bytes, self.total_bytes))
|
||||||
pub fn percent(self) -> Option<f32> {
|
|
||||||
Some(if self.success() {
|
|
||||||
100.0
|
|
||||||
} else if self.failed() {
|
|
||||||
0.0
|
|
||||||
} else if self.total_bytes != 0 {
|
|
||||||
99.99f32.min(self.processed_bytes as f32 / self.total_bytes as f32 * 100.0)
|
|
||||||
} else {
|
|
||||||
99.99
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -112,7 +88,7 @@ impl FileProgCut {
|
||||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize)]
|
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize)]
|
||||||
pub struct FileProgLink {
|
pub struct FileProgLink {
|
||||||
pub state: Option<bool>,
|
pub state: Option<bool>,
|
||||||
pub cleaned: Option<bool>,
|
pub cleaned: CleanupState,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<FileProgLink> for TaskSummary {
|
impl From<FileProgLink> for TaskSummary {
|
||||||
|
|
@ -126,18 +102,14 @@ impl From<FileProgLink> for TaskSummary {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FileProgLink {
|
impl Progress for FileProgLink {
|
||||||
pub fn cooked(self) -> bool { self.state == Some(true) }
|
fn running(self) -> bool { self.cooking_or_cleaning(self.state.is_none()) }
|
||||||
|
|
||||||
pub fn running(self) -> bool { self.state.is_none() || (self.cleaned.is_none() && self.cooked()) }
|
fn cooked(self) -> bool { self.state == Some(true) }
|
||||||
|
|
||||||
pub fn success(self) -> bool { self.cleaned == Some(true) && self.cooked() }
|
fn failed(self) -> bool { self.cleaned.is_failed() || self.state == Some(false) }
|
||||||
|
|
||||||
pub fn failed(self) -> bool { self.cleaned == Some(false) || self.state == Some(false) }
|
fn cleaned(self) -> Option<CleanupState> { Some(self.cleaned) }
|
||||||
|
|
||||||
pub fn cleaned(self) -> Option<bool> { self.cleaned }
|
|
||||||
|
|
||||||
pub fn percent(self) -> Option<f32> { None }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Hardlink
|
// --- Hardlink
|
||||||
|
|
@ -147,7 +119,7 @@ pub struct FileProgHardlink {
|
||||||
pub success: u32,
|
pub success: u32,
|
||||||
pub failed: u32,
|
pub failed: u32,
|
||||||
pub collected: Option<bool>,
|
pub collected: Option<bool>,
|
||||||
pub cleaned: Option<bool>,
|
pub cleaned: CleanupState,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<FileProgHardlink> for TaskSummary {
|
impl From<FileProgHardlink> for TaskSummary {
|
||||||
|
|
@ -161,22 +133,16 @@ impl From<FileProgHardlink> for TaskSummary {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FileProgHardlink {
|
impl Progress for FileProgHardlink {
|
||||||
pub fn cooked(self) -> bool { self.collected == Some(true) && self.success == self.total }
|
fn running(self) -> bool {
|
||||||
|
self.cooking_or_cleaning(self.collected.is_none() || self.success + self.failed != self.total)
|
||||||
pub fn running(self) -> bool {
|
|
||||||
self.collected.is_none()
|
|
||||||
|| self.success + self.failed != self.total
|
|
||||||
|| (self.cleaned.is_none() && self.cooked())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn success(self) -> bool { self.cleaned == Some(true) && self.cooked() }
|
fn cooked(self) -> bool { self.collected == Some(true) && self.success == self.total }
|
||||||
|
|
||||||
pub fn failed(self) -> bool { self.cleaned == Some(false) || self.collected == Some(false) }
|
fn failed(self) -> bool { self.cleaned.is_failed() || self.collected == Some(false) }
|
||||||
|
|
||||||
pub fn cleaned(self) -> Option<bool> { self.cleaned }
|
fn cleaned(self) -> Option<CleanupState> { Some(self.cleaned) }
|
||||||
|
|
||||||
pub fn percent(self) -> Option<f32> { None }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Delete
|
// --- Delete
|
||||||
|
|
@ -188,7 +154,7 @@ pub struct FileProgDelete {
|
||||||
pub total_bytes: u64,
|
pub total_bytes: u64,
|
||||||
pub processed_bytes: u64,
|
pub processed_bytes: u64,
|
||||||
pub collected: Option<bool>,
|
pub collected: Option<bool>,
|
||||||
pub cleaned: Option<bool>,
|
pub cleaned: CleanupState,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<FileProgDelete> for TaskSummary {
|
impl From<FileProgDelete> for TaskSummary {
|
||||||
|
|
@ -202,33 +168,21 @@ impl From<FileProgDelete> for TaskSummary {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FileProgDelete {
|
impl Progress for FileProgDelete {
|
||||||
pub fn cooked(self) -> bool {
|
fn running(self) -> bool {
|
||||||
self.collected == Some(true) && self.success_files == self.total_files
|
self.cooking_or_cleaning(
|
||||||
|
self.collected.is_none() || self.success_files + self.failed_files != self.total_files,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn running(self) -> bool {
|
fn cooked(self) -> bool { self.collected == Some(true) && self.success_files == self.total_files }
|
||||||
self.collected.is_none()
|
|
||||||
|| self.success_files + self.failed_files != self.total_files
|
|
||||||
|| (self.cleaned.is_none() && self.cooked())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn success(self) -> bool { self.cleaned == Some(true) && self.cooked() }
|
fn failed(self) -> bool { self.cleaned.is_failed() || self.collected == Some(false) }
|
||||||
|
|
||||||
pub fn failed(self) -> bool { self.cleaned == Some(false) || self.collected == Some(false) }
|
fn cleaned(self) -> Option<CleanupState> { Some(self.cleaned) }
|
||||||
|
|
||||||
pub fn cleaned(self) -> Option<bool> { self.cleaned }
|
fn percent(self) -> Option<f32> {
|
||||||
|
Some(self.byte_percent(self.processed_bytes, self.total_bytes))
|
||||||
pub fn percent(self) -> Option<f32> {
|
|
||||||
Some(if self.success() {
|
|
||||||
100.0
|
|
||||||
} else if self.failed() {
|
|
||||||
0.0
|
|
||||||
} else if self.total_bytes != 0 {
|
|
||||||
99.99f32.min(self.processed_bytes as f32 / self.total_bytes as f32 * 100.0)
|
|
||||||
} else {
|
|
||||||
99.99
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -236,7 +190,7 @@ impl FileProgDelete {
|
||||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize)]
|
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize)]
|
||||||
pub struct FileProgTrash {
|
pub struct FileProgTrash {
|
||||||
pub state: Option<bool>,
|
pub state: Option<bool>,
|
||||||
pub cleaned: Option<bool>,
|
pub cleaned: CleanupState,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<FileProgTrash> for TaskSummary {
|
impl From<FileProgTrash> for TaskSummary {
|
||||||
|
|
@ -250,18 +204,14 @@ impl From<FileProgTrash> for TaskSummary {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FileProgTrash {
|
impl Progress for FileProgTrash {
|
||||||
pub fn cooked(self) -> bool { self.state == Some(true) }
|
fn running(self) -> bool { self.cooking_or_cleaning(self.state.is_none()) }
|
||||||
|
|
||||||
pub fn running(self) -> bool { self.state.is_none() || (self.cleaned.is_none() && self.cooked()) }
|
fn cooked(self) -> bool { self.state == Some(true) }
|
||||||
|
|
||||||
pub fn success(self) -> bool { self.cleaned == Some(true) && self.cooked() }
|
fn failed(self) -> bool { self.cleaned.is_failed() || self.state == Some(false) }
|
||||||
|
|
||||||
pub fn failed(self) -> bool { self.cleaned == Some(false) || self.state == Some(false) }
|
fn cleaned(self) -> Option<CleanupState> { Some(self.cleaned) }
|
||||||
|
|
||||||
pub fn cleaned(self) -> Option<bool> { self.cleaned }
|
|
||||||
|
|
||||||
pub fn percent(self) -> Option<f32> { None }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Download
|
// --- Download
|
||||||
|
|
@ -273,7 +223,7 @@ pub struct FileProgDownload {
|
||||||
pub total_bytes: u64,
|
pub total_bytes: u64,
|
||||||
pub processed_bytes: u64,
|
pub processed_bytes: u64,
|
||||||
pub collected: Option<bool>,
|
pub collected: Option<bool>,
|
||||||
pub cleaned: Option<bool>,
|
pub cleaned: CleanupState,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<FileProgDownload> for TaskSummary {
|
impl From<FileProgDownload> for TaskSummary {
|
||||||
|
|
@ -287,33 +237,21 @@ impl From<FileProgDownload> for TaskSummary {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FileProgDownload {
|
impl Progress for FileProgDownload {
|
||||||
pub fn cooked(self) -> bool {
|
fn running(self) -> bool {
|
||||||
self.collected == Some(true) && self.success_files == self.total_files
|
self.cooking_or_cleaning(
|
||||||
|
self.collected.is_none() || self.success_files + self.failed_files != self.total_files,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn running(self) -> bool {
|
fn cooked(self) -> bool { self.collected == Some(true) && self.success_files == self.total_files }
|
||||||
self.collected.is_none()
|
|
||||||
|| self.success_files + self.failed_files != self.total_files
|
|
||||||
|| (self.cleaned.is_none() && self.cooked())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn success(self) -> bool { self.cleaned == Some(true) && self.cooked() }
|
fn failed(self) -> bool { self.cleaned.is_failed() || self.collected == Some(false) }
|
||||||
|
|
||||||
pub fn failed(self) -> bool { self.cleaned == Some(false) || self.collected == Some(false) }
|
fn cleaned(self) -> Option<CleanupState> { Some(self.cleaned) }
|
||||||
|
|
||||||
pub fn cleaned(self) -> Option<bool> { self.cleaned }
|
fn percent(self) -> Option<f32> {
|
||||||
|
Some(self.byte_percent(self.processed_bytes, self.total_bytes))
|
||||||
pub fn percent(self) -> Option<f32> {
|
|
||||||
Some(if self.success() {
|
|
||||||
100.0
|
|
||||||
} else if self.failed() {
|
|
||||||
0.0
|
|
||||||
} else if self.total_bytes != 0 {
|
|
||||||
99.99f32.min(self.processed_bytes as f32 / self.total_bytes as f32 * 100.0)
|
|
||||||
} else {
|
|
||||||
99.99
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -326,7 +264,7 @@ pub struct FileProgUpload {
|
||||||
pub total_bytes: u64,
|
pub total_bytes: u64,
|
||||||
pub processed_bytes: u64,
|
pub processed_bytes: u64,
|
||||||
pub collected: Option<bool>,
|
pub collected: Option<bool>,
|
||||||
pub cleaned: Option<bool>,
|
pub cleaned: CleanupState,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<FileProgUpload> for TaskSummary {
|
impl From<FileProgUpload> for TaskSummary {
|
||||||
|
|
@ -340,32 +278,20 @@ impl From<FileProgUpload> for TaskSummary {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FileProgUpload {
|
impl Progress for FileProgUpload {
|
||||||
pub fn cooked(self) -> bool {
|
fn running(self) -> bool {
|
||||||
self.collected == Some(true) && self.success_files == self.total_files
|
self.cooking_or_cleaning(
|
||||||
|
self.collected.is_none() || self.success_files + self.failed_files != self.total_files,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn running(self) -> bool {
|
fn cooked(self) -> bool { self.collected == Some(true) && self.success_files == self.total_files }
|
||||||
self.collected.is_none()
|
|
||||||
|| self.success_files + self.failed_files != self.total_files
|
|
||||||
|| (self.cleaned.is_none() && self.cooked())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn success(self) -> bool { self.cleaned == Some(true) && self.cooked() }
|
fn failed(self) -> bool { self.cleaned.is_failed() || self.collected == Some(false) }
|
||||||
|
|
||||||
pub fn failed(self) -> bool { self.cleaned == Some(false) || self.collected == Some(false) }
|
fn cleaned(self) -> Option<CleanupState> { Some(self.cleaned) }
|
||||||
|
|
||||||
pub fn cleaned(self) -> Option<bool> { self.cleaned }
|
fn percent(self) -> Option<f32> {
|
||||||
|
Some(self.byte_percent(self.processed_bytes, self.total_bytes))
|
||||||
pub fn percent(self) -> Option<f32> {
|
|
||||||
Some(if self.success() {
|
|
||||||
100.0
|
|
||||||
} else if self.failed() {
|
|
||||||
0.0
|
|
||||||
} else if self.total_bytes != 0 {
|
|
||||||
99.99f32.min(self.processed_bytes as f32 / self.total_bytes as f32 * 100.0)
|
|
||||||
} else {
|
|
||||||
99.99
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ mod macros;
|
||||||
|
|
||||||
yazi_macro::mod_pub!(fetch file hook plugin preload process size);
|
yazi_macro::mod_pub!(fetch file hook plugin preload process size);
|
||||||
|
|
||||||
yazi_macro::mod_flat!(behavior ongoing op out progress proxy scheduler snap summary task worker);
|
yazi_macro::mod_flat!(behavior cleanup ongoing op out progress proxy scheduler snap summary task worker);
|
||||||
|
|
||||||
const LOW: u8 = yazi_config::Priority::Low as u8;
|
const LOW: u8 = yazi_config::Priority::Low as u8;
|
||||||
const NORMAL: u8 = yazi_config::Priority::Normal as u8;
|
const NORMAL: u8 = yazi_config::Priority::Normal as u8;
|
||||||
|
|
|
||||||
|
|
@ -45,3 +45,30 @@ macro_rules! impl_from_prog {
|
||||||
)*
|
)*
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! dispatch_progress {
|
||||||
|
($value:expr, $method:ident) => {
|
||||||
|
match $value {
|
||||||
|
// File
|
||||||
|
$crate::TaskProg::FileCopy(p) => $crate::Progress::$method(p),
|
||||||
|
$crate::TaskProg::FileCut(p) => $crate::Progress::$method(p),
|
||||||
|
$crate::TaskProg::FileLink(p) => $crate::Progress::$method(p),
|
||||||
|
$crate::TaskProg::FileHardlink(p) => $crate::Progress::$method(p),
|
||||||
|
$crate::TaskProg::FileDelete(p) => $crate::Progress::$method(p),
|
||||||
|
$crate::TaskProg::FileTrash(p) => $crate::Progress::$method(p),
|
||||||
|
$crate::TaskProg::FileDownload(p) => $crate::Progress::$method(p),
|
||||||
|
$crate::TaskProg::FileUpload(p) => $crate::Progress::$method(p),
|
||||||
|
// Plugin
|
||||||
|
$crate::TaskProg::PluginEntry(p) => $crate::Progress::$method(p),
|
||||||
|
// Prework
|
||||||
|
$crate::TaskProg::Fetch(p) => $crate::Progress::$method(p),
|
||||||
|
$crate::TaskProg::Preload(p) => $crate::Progress::$method(p),
|
||||||
|
$crate::TaskProg::Size(p) => $crate::Progress::$method(p),
|
||||||
|
// Process
|
||||||
|
$crate::TaskProg::ProcessBlock(p) => $crate::Progress::$method(p),
|
||||||
|
$crate::TaskProg::ProcessOrphan(p) => $crate::Progress::$method(p),
|
||||||
|
$crate::TaskProg::ProcessBg(p) => $crate::Progress::$method(p),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::TaskSummary;
|
use crate::{Progress, TaskSummary};
|
||||||
|
|
||||||
// --- Entry
|
// --- Entry
|
||||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize)]
|
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize)]
|
||||||
|
|
@ -19,16 +19,10 @@ impl From<PluginProgEntry> for TaskSummary {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PluginProgEntry {
|
impl Progress for PluginProgEntry {
|
||||||
pub fn cooked(self) -> bool { self.state == Some(true) }
|
fn running(self) -> bool { self.state.is_none() }
|
||||||
|
|
||||||
pub fn running(self) -> bool { self.state.is_none() }
|
fn cooked(self) -> bool { self.state == Some(true) }
|
||||||
|
|
||||||
pub fn success(self) -> bool { self.cooked() }
|
fn failed(self) -> bool { self.state == Some(false) }
|
||||||
|
|
||||||
pub fn failed(self) -> bool { self.state == Some(false) }
|
|
||||||
|
|
||||||
pub fn cleaned(self) -> Option<bool> { None }
|
|
||||||
|
|
||||||
pub fn percent(self) -> Option<f32> { None }
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use yazi_runner::preloader::PreloadError;
|
use yazi_runner::preloader::PreloadError;
|
||||||
|
|
||||||
use crate::{Task, TaskProg};
|
use crate::{CleanupState, Task, TaskProg};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) enum PreloadOut {
|
pub(crate) enum PreloadOut {
|
||||||
|
|
@ -25,7 +25,7 @@ impl PreloadOut {
|
||||||
task.log(reason);
|
task.log(reason);
|
||||||
}
|
}
|
||||||
Self::Clean => {
|
Self::Clean => {
|
||||||
prog.cleaned = Some(true);
|
prog.cleaned = CleanupState::Success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::TaskSummary;
|
use crate::{CleanupState, Progress, TaskSummary};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize)]
|
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize)]
|
||||||
pub struct PreloadProg {
|
pub struct PreloadProg {
|
||||||
pub state: Option<bool>,
|
pub state: Option<bool>,
|
||||||
pub cleaned: Option<bool>,
|
pub cleaned: CleanupState,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<PreloadProg> for TaskSummary {
|
impl From<PreloadProg> for TaskSummary {
|
||||||
|
|
@ -19,16 +19,12 @@ impl From<PreloadProg> for TaskSummary {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PreloadProg {
|
impl Progress for PreloadProg {
|
||||||
pub fn cooked(self) -> bool { self.state == Some(true) }
|
fn running(self) -> bool { self.cooking_or_cleaning(self.state.is_none()) }
|
||||||
|
|
||||||
pub fn running(self) -> bool { self.state.is_none() || (self.cleaned.is_none() && self.cooked()) }
|
fn cooked(self) -> bool { self.state == Some(true) }
|
||||||
|
|
||||||
pub fn success(self) -> bool { self.cleaned == Some(true) && self.cooked() }
|
fn failed(self) -> bool { self.cleaned.is_failed() || self.state == Some(false) }
|
||||||
|
|
||||||
pub fn failed(self) -> bool { self.cleaned == Some(false) || self.state == Some(false) }
|
fn cleaned(self) -> Option<CleanupState> { Some(self.cleaned) }
|
||||||
|
|
||||||
pub fn cleaned(self) -> Option<bool> { self.cleaned }
|
|
||||||
|
|
||||||
pub fn percent(self) -> Option<f32> { None }
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::TaskSummary;
|
use crate::{Progress, TaskSummary};
|
||||||
|
|
||||||
// --- Block
|
// --- Block
|
||||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize)]
|
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize)]
|
||||||
|
|
@ -19,18 +19,12 @@ impl From<ProcessProgBlock> for TaskSummary {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProcessProgBlock {
|
impl Progress for ProcessProgBlock {
|
||||||
pub fn cooked(self) -> bool { self.state == Some(true) }
|
fn running(self) -> bool { self.state.is_none() }
|
||||||
|
|
||||||
pub fn running(self) -> bool { self.state.is_none() }
|
fn cooked(self) -> bool { self.state == Some(true) }
|
||||||
|
|
||||||
pub fn success(self) -> bool { self.cooked() }
|
fn failed(self) -> bool { self.state == Some(false) }
|
||||||
|
|
||||||
pub fn failed(self) -> bool { self.state == Some(false) }
|
|
||||||
|
|
||||||
pub fn cleaned(self) -> Option<bool> { None }
|
|
||||||
|
|
||||||
pub fn percent(self) -> Option<f32> { None }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Orphan
|
// --- Orphan
|
||||||
|
|
@ -50,18 +44,12 @@ impl From<ProcessProgOrphan> for TaskSummary {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProcessProgOrphan {
|
impl Progress for ProcessProgOrphan {
|
||||||
pub fn cooked(self) -> bool { self.state == Some(true) }
|
fn running(self) -> bool { self.state.is_none() }
|
||||||
|
|
||||||
pub fn running(self) -> bool { self.state.is_none() }
|
fn cooked(self) -> bool { self.state == Some(true) }
|
||||||
|
|
||||||
pub fn success(self) -> bool { self.cooked() }
|
fn failed(self) -> bool { self.state == Some(false) }
|
||||||
|
|
||||||
pub fn failed(self) -> bool { self.state == Some(false) }
|
|
||||||
|
|
||||||
pub fn cleaned(self) -> Option<bool> { None }
|
|
||||||
|
|
||||||
pub fn percent(self) -> Option<f32> { None }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Bg
|
// --- Bg
|
||||||
|
|
@ -81,16 +69,10 @@ impl From<ProcessProgBg> for TaskSummary {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ProcessProgBg {
|
impl Progress for ProcessProgBg {
|
||||||
pub fn cooked(self) -> bool { self.state == Some(true) }
|
fn running(self) -> bool { self.state.is_none() }
|
||||||
|
|
||||||
pub fn running(self) -> bool { self.state.is_none() }
|
fn cooked(self) -> bool { self.state == Some(true) }
|
||||||
|
|
||||||
pub fn success(self) -> bool { self.cooked() }
|
fn failed(self) -> bool { self.state == Some(false) }
|
||||||
|
|
||||||
pub fn failed(self) -> bool { self.state == Some(false) }
|
|
||||||
|
|
||||||
pub fn cleaned(self) -> Option<bool> { None }
|
|
||||||
|
|
||||||
pub fn percent(self) -> Option<f32> { None }
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,57 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::{TaskSummary, fetch::FetchProg, file::{FileProgCopy, FileProgCut, FileProgDelete, FileProgDownload, FileProgHardlink, FileProgLink, FileProgTrash, FileProgUpload}, impl_from_prog, plugin::PluginProgEntry, preload::PreloadProg, process::{ProcessProgBg, ProcessProgBlock, ProcessProgOrphan}, size::SizeProg};
|
use crate::{CleanupState, TaskSummary, dispatch_progress, fetch::FetchProg, file::{FileProgCopy, FileProgCut, FileProgDelete, FileProgDownload, FileProgHardlink, FileProgLink, FileProgTrash, FileProgUpload}, impl_from_prog, plugin::PluginProgEntry, preload::PreloadProg, process::{ProcessProgBg, ProcessProgBlock, ProcessProgOrphan}, size::SizeProg};
|
||||||
|
|
||||||
|
pub trait Progress: Copy {
|
||||||
|
// Whether the task is still cooking or cleaning.
|
||||||
|
fn running(self) -> bool;
|
||||||
|
|
||||||
|
// Whether the task succeeded, regardless cleanup.
|
||||||
|
// For tasks without a cleanup, this is the same as `success()`.
|
||||||
|
fn cooked(self) -> bool;
|
||||||
|
|
||||||
|
// Whether the task fully succeeded, including cleanup if applicable.
|
||||||
|
fn success(self) -> bool {
|
||||||
|
match self.cleaned() {
|
||||||
|
None | Some(CleanupState::Success) => self.cooked(),
|
||||||
|
Some(CleanupState::Pending | CleanupState::Failed) => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Whether the task fully failed.
|
||||||
|
//
|
||||||
|
// For tasks with a collect phase, e.g. gathering files to copy:
|
||||||
|
// collect failed, or cleanup failed if applicable, regardless main work.
|
||||||
|
// For tasks without a collect phase:
|
||||||
|
// main work failed, or cleanup failed if applicable.
|
||||||
|
fn failed(self) -> bool;
|
||||||
|
|
||||||
|
// Cleanup state if the task has a cleanup phase, otherwise `None`.
|
||||||
|
fn cleaned(self) -> Option<CleanupState> { None }
|
||||||
|
|
||||||
|
// Optional percentage for UI display.
|
||||||
|
fn percent(self) -> Option<f32> { None }
|
||||||
|
|
||||||
|
// Helper for tasks that are still cooking or cleaning.
|
||||||
|
fn cooking_or_cleaning(self, cooking: bool) -> bool {
|
||||||
|
cooking || (self.cooked() && self.cleaned() == Some(CleanupState::Pending))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper for byte-based progress calculations used by file transfer tasks.
|
||||||
|
fn byte_percent(self, processed_bytes: u64, total_bytes: u64) -> f32 {
|
||||||
|
if self.success() {
|
||||||
|
100.0
|
||||||
|
} else if self.failed() {
|
||||||
|
0.0
|
||||||
|
} else if total_bytes != 0 {
|
||||||
|
99.99f32.min(processed_bytes as f32 / total_bytes as f32 * 100.0)
|
||||||
|
} else {
|
||||||
|
99.99
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- TaskProg
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize)]
|
||||||
#[serde(tag = "kind")]
|
#[serde(tag = "kind")]
|
||||||
pub enum TaskProg {
|
pub enum TaskProg {
|
||||||
|
|
@ -69,151 +119,21 @@ impl From<TaskProg> for TaskSummary {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Progress for TaskProg {
|
||||||
|
fn running(self) -> bool { dispatch_progress!(self, running) }
|
||||||
|
|
||||||
|
fn cooked(self) -> bool { dispatch_progress!(self, cooked) }
|
||||||
|
|
||||||
|
fn success(self) -> bool { dispatch_progress!(self, success) }
|
||||||
|
|
||||||
|
fn failed(self) -> bool { dispatch_progress!(self, failed) }
|
||||||
|
|
||||||
|
fn cleaned(self) -> Option<CleanupState> { dispatch_progress!(self, cleaned) }
|
||||||
|
|
||||||
|
fn percent(self) -> Option<f32> { dispatch_progress!(self, percent) }
|
||||||
|
}
|
||||||
|
|
||||||
impl TaskProg {
|
impl TaskProg {
|
||||||
pub fn cooked(self) -> bool {
|
|
||||||
match self {
|
|
||||||
// File
|
|
||||||
Self::FileCopy(p) => p.cooked(),
|
|
||||||
Self::FileCut(p) => p.cooked(),
|
|
||||||
Self::FileLink(p) => p.cooked(),
|
|
||||||
Self::FileHardlink(p) => p.cooked(),
|
|
||||||
Self::FileDelete(p) => p.cooked(),
|
|
||||||
Self::FileTrash(p) => p.cooked(),
|
|
||||||
Self::FileDownload(p) => p.cooked(),
|
|
||||||
Self::FileUpload(p) => p.cooked(),
|
|
||||||
// Plugin
|
|
||||||
Self::PluginEntry(p) => p.cooked(),
|
|
||||||
// Prework
|
|
||||||
Self::Fetch(p) => p.cooked(),
|
|
||||||
Self::Preload(p) => p.cooked(),
|
|
||||||
Self::Size(p) => p.cooked(),
|
|
||||||
// Process
|
|
||||||
Self::ProcessBlock(p) => p.cooked(),
|
|
||||||
Self::ProcessOrphan(p) => p.cooked(),
|
|
||||||
Self::ProcessBg(p) => p.cooked(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn running(self) -> bool {
|
|
||||||
match self {
|
|
||||||
// File
|
|
||||||
Self::FileCopy(p) => p.running(),
|
|
||||||
Self::FileCut(p) => p.running(),
|
|
||||||
Self::FileLink(p) => p.running(),
|
|
||||||
Self::FileHardlink(p) => p.running(),
|
|
||||||
Self::FileDelete(p) => p.running(),
|
|
||||||
Self::FileTrash(p) => p.running(),
|
|
||||||
Self::FileDownload(p) => p.running(),
|
|
||||||
Self::FileUpload(p) => p.running(),
|
|
||||||
// Plugin
|
|
||||||
Self::PluginEntry(p) => p.running(),
|
|
||||||
// Prework
|
|
||||||
Self::Fetch(p) => p.running(),
|
|
||||||
Self::Preload(p) => p.running(),
|
|
||||||
Self::Size(p) => p.running(),
|
|
||||||
// Process
|
|
||||||
Self::ProcessBlock(p) => p.running(),
|
|
||||||
Self::ProcessOrphan(p) => p.running(),
|
|
||||||
Self::ProcessBg(p) => p.running(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn success(self) -> bool {
|
|
||||||
match self {
|
|
||||||
// File
|
|
||||||
Self::FileCopy(p) => p.success(),
|
|
||||||
Self::FileCut(p) => p.success(),
|
|
||||||
Self::FileLink(p) => p.success(),
|
|
||||||
Self::FileHardlink(p) => p.success(),
|
|
||||||
Self::FileDelete(p) => p.success(),
|
|
||||||
Self::FileTrash(p) => p.success(),
|
|
||||||
Self::FileDownload(p) => p.success(),
|
|
||||||
Self::FileUpload(p) => p.success(),
|
|
||||||
// Plugin
|
|
||||||
Self::PluginEntry(p) => p.success(),
|
|
||||||
// Prework
|
|
||||||
Self::Fetch(p) => p.success(),
|
|
||||||
Self::Preload(p) => p.success(),
|
|
||||||
Self::Size(p) => p.success(),
|
|
||||||
// Process
|
|
||||||
Self::ProcessBlock(p) => p.success(),
|
|
||||||
Self::ProcessOrphan(p) => p.success(),
|
|
||||||
Self::ProcessBg(p) => p.success(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn failed(self) -> bool {
|
|
||||||
match self {
|
|
||||||
// File
|
|
||||||
Self::FileCopy(p) => p.failed(),
|
|
||||||
Self::FileCut(p) => p.failed(),
|
|
||||||
Self::FileLink(p) => p.failed(),
|
|
||||||
Self::FileHardlink(p) => p.failed(),
|
|
||||||
Self::FileDelete(p) => p.failed(),
|
|
||||||
Self::FileTrash(p) => p.failed(),
|
|
||||||
Self::FileDownload(p) => p.failed(),
|
|
||||||
Self::FileUpload(p) => p.failed(),
|
|
||||||
// Plugin
|
|
||||||
Self::PluginEntry(p) => p.failed(),
|
|
||||||
// Prework
|
|
||||||
Self::Fetch(p) => p.failed(),
|
|
||||||
Self::Preload(p) => p.failed(),
|
|
||||||
Self::Size(p) => p.failed(),
|
|
||||||
// Process
|
|
||||||
Self::ProcessBlock(p) => p.failed(),
|
|
||||||
Self::ProcessOrphan(p) => p.failed(),
|
|
||||||
Self::ProcessBg(p) => p.failed(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn cleaned(self) -> Option<bool> {
|
|
||||||
match self {
|
|
||||||
// File
|
|
||||||
Self::FileCopy(p) => p.cleaned(),
|
|
||||||
Self::FileCut(p) => p.cleaned(),
|
|
||||||
Self::FileLink(p) => p.cleaned(),
|
|
||||||
Self::FileHardlink(p) => p.cleaned(),
|
|
||||||
Self::FileDelete(p) => p.cleaned(),
|
|
||||||
Self::FileTrash(p) => p.cleaned(),
|
|
||||||
Self::FileDownload(p) => p.cleaned(),
|
|
||||||
Self::FileUpload(p) => p.cleaned(),
|
|
||||||
// Plugin
|
|
||||||
Self::PluginEntry(p) => p.cleaned(),
|
|
||||||
// Prework
|
|
||||||
Self::Fetch(p) => p.cleaned(),
|
|
||||||
Self::Preload(p) => p.cleaned(),
|
|
||||||
Self::Size(p) => p.cleaned(),
|
|
||||||
// Process
|
|
||||||
Self::ProcessBlock(p) => p.cleaned(),
|
|
||||||
Self::ProcessOrphan(p) => p.cleaned(),
|
|
||||||
Self::ProcessBg(p) => p.cleaned(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn percent(self) -> Option<f32> {
|
|
||||||
match self {
|
|
||||||
// File
|
|
||||||
Self::FileCopy(p) => p.percent(),
|
|
||||||
Self::FileCut(p) => p.percent(),
|
|
||||||
Self::FileLink(p) => p.percent(),
|
|
||||||
Self::FileHardlink(p) => p.percent(),
|
|
||||||
Self::FileDelete(p) => p.percent(),
|
|
||||||
Self::FileTrash(p) => p.percent(),
|
|
||||||
Self::FileDownload(p) => p.percent(),
|
|
||||||
Self::FileUpload(p) => p.percent(),
|
|
||||||
// Plugin
|
|
||||||
Self::PluginEntry(p) => p.percent(),
|
|
||||||
// Prework
|
|
||||||
Self::Fetch(p) => p.percent(),
|
|
||||||
Self::Preload(p) => p.percent(),
|
|
||||||
Self::Size(p) => p.percent(),
|
|
||||||
// Process
|
|
||||||
Self::ProcessBlock(p) => p.percent(),
|
|
||||||
Self::ProcessOrphan(p) => p.percent(),
|
|
||||||
Self::ProcessBg(p) => p.percent(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn is_user(self) -> bool {
|
pub(crate) fn is_user(self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
// File
|
// File
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::TaskSummary;
|
use crate::{Progress, TaskSummary};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize)]
|
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize)]
|
||||||
pub struct SizeProg {
|
pub struct SizeProg {
|
||||||
|
|
@ -18,16 +18,10 @@ impl From<SizeProg> for TaskSummary {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SizeProg {
|
impl Progress for SizeProg {
|
||||||
pub fn cooked(self) -> bool { self.done }
|
fn running(self) -> bool { !self.done }
|
||||||
|
|
||||||
pub fn running(self) -> bool { !self.done }
|
fn cooked(self) -> bool { self.done }
|
||||||
|
|
||||||
pub fn success(self) -> bool { self.cooked() }
|
fn failed(self) -> bool { false }
|
||||||
|
|
||||||
pub fn failed(self) -> bool { false }
|
|
||||||
|
|
||||||
pub fn cleaned(self) -> Option<bool> { None }
|
|
||||||
|
|
||||||
pub fn percent(self) -> Option<f32> { None }
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use ordered_float::OrderedFloat;
|
use ordered_float::OrderedFloat;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use crate::Ongoing;
|
use crate::{Ongoing, Progress};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize)]
|
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize)]
|
||||||
pub struct TaskSummary {
|
pub struct TaskSummary {
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ use parking_lot::Mutex;
|
||||||
use tokio::{select, sync::mpsc, task::JoinHandle};
|
use tokio::{select, sync::mpsc, task::JoinHandle};
|
||||||
use yazi_config::YAZI;
|
use yazi_config::YAZI;
|
||||||
|
|
||||||
use crate::{LOW, Ongoing, TaskOp, TaskOps, TaskOut, fetch::{Fetch, FetchIn}, file::{File, FileIn}, hook::{Hook, HookIn}, plugin::{Plugin, PluginIn}, preload::{Preload, PreloadIn}, process::{Process, ProcessIn}, size::{Size, SizeIn}};
|
use crate::{CleanupState, LOW, Ongoing, Progress, TaskOp, TaskOps, TaskOut, fetch::{Fetch, FetchIn}, file::{File, FileIn}, hook::{Hook, HookIn}, plugin::{Plugin, PluginIn}, preload::{Preload, PreloadIn}, process::{Process, ProcessIn}, size::{Size, SizeIn}};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Worker {
|
pub struct Worker {
|
||||||
|
|
@ -282,7 +282,7 @@ impl Worker {
|
||||||
op.out.reduce(task);
|
op.out.reduce(task);
|
||||||
if !task.prog.cooked() && task.done.completed() != Some(false) {
|
if !task.prog.cooked() && task.done.completed() != Some(false) {
|
||||||
continue; // Not cooked yet, also not canceled
|
continue; // Not cooked yet, also not canceled
|
||||||
} else if task.prog.cleaned() == Some(false) {
|
} else if task.prog.cleaned() == Some(CleanupState::Failed) {
|
||||||
continue; // Failed to clean up
|
continue; // Failed to clean up
|
||||||
} else if let Some(hook) = task.hook.take() {
|
} else if let Some(hook) = task.hook.take() {
|
||||||
me.hook.submit(hook, LOW);
|
me.hook.submit(hook, LOW);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue