mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-22 15:21:04 +00:00
refactor: integrate tasks into scheduler (#406)
This commit is contained in:
parent
b41bea9e8f
commit
6d29420e2f
57 changed files with 230 additions and 164 deletions
26
Cargo.lock
generated
26
Cargo.lock
generated
|
|
@ -2554,9 +2554,7 @@ name = "yazi-core"
|
|||
version = "0.1.5"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-channel",
|
||||
"bitflags 2.4.1",
|
||||
"clipboard-win",
|
||||
"crossterm",
|
||||
"futures",
|
||||
"indexmap",
|
||||
|
|
@ -2566,16 +2564,15 @@ dependencies = [
|
|||
"ratatui",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"syntect",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tracing",
|
||||
"trash",
|
||||
"unicode-width",
|
||||
"yazi-adaptor",
|
||||
"yazi-config",
|
||||
"yazi-prebuild",
|
||||
"yazi-scheduler",
|
||||
"yazi-shared",
|
||||
]
|
||||
|
||||
|
|
@ -2625,6 +2622,27 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "394457709d77af570fcb3c0ef878336213b4e9c8f298eccde728aecd602aa7e0"
|
||||
|
||||
[[package]]
|
||||
name = "yazi-scheduler"
|
||||
version = "0.1.5"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-channel",
|
||||
"clipboard-win",
|
||||
"futures",
|
||||
"libc",
|
||||
"parking_lot",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"trash",
|
||||
"yazi-adaptor",
|
||||
"yazi-config",
|
||||
"yazi-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yazi-shared"
|
||||
version = "0.1.5"
|
||||
|
|
|
|||
|
|
@ -9,13 +9,13 @@ homepage = "https://yazi-rs.github.io"
|
|||
repository = "https://github.com/sxyazi/yazi"
|
||||
|
||||
[dependencies]
|
||||
yazi-adaptor = { path = "../yazi-adaptor", version = "0.1.5" }
|
||||
yazi-config = { path = "../yazi-config", version = "0.1.5" }
|
||||
yazi-shared = { path = "../yazi-shared", version = "0.1.5" }
|
||||
yazi-adaptor = { path = "../yazi-adaptor", version = "0.1.5" }
|
||||
yazi-config = { path = "../yazi-config", version = "0.1.5" }
|
||||
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"
|
||||
|
|
@ -26,16 +26,11 @@ 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"
|
||||
|
||||
# Logging
|
||||
tracing = { version = "^0", features = [ "max_level_debug", "release_max_level_warn" ] }
|
||||
|
||||
[target."cfg(windows)".dependencies]
|
||||
clipboard-win = "^4"
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::{collections::{BTreeMap, BTreeSet}, mem, ops::Deref, sync::atomic::Orde
|
|||
use anyhow::Result;
|
||||
use tokio::{fs, select, sync::mpsc::{self, UnboundedReceiver}};
|
||||
use yazi_config::{manager::SortBy, MANAGER};
|
||||
use yazi_shared::{files::{File, FILES_TICKET}, fs::Url};
|
||||
use yazi_shared::fs::{File, Url, FILES_TICKET};
|
||||
|
||||
use super::FilesSorter;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::{cmp::Ordering, collections::BTreeMap, mem};
|
||||
|
||||
use yazi_config::manager::SortBy;
|
||||
use yazi_shared::{files::File, fs::Url, natsort};
|
||||
use yazi_shared::{fs::File, fs::Url, natsort};
|
||||
|
||||
#[derive(Clone, Copy, Default, PartialEq)]
|
||||
pub struct FilesSorter {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use yazi_scheduler::external;
|
||||
use yazi_shared::event::Exec;
|
||||
|
||||
use crate::{external, input::{op::InputOp, Input}};
|
||||
use crate::input::{op::InputOp, Input};
|
||||
|
||||
pub struct Opt {
|
||||
before: bool,
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ use std::ops::Range;
|
|||
use tokio::sync::mpsc::UnboundedSender;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
use yazi_config::{popup::Position, INPUT};
|
||||
use yazi_scheduler::external;
|
||||
use yazi_shared::InputError;
|
||||
|
||||
use super::{mode::InputMode, op::InputOp, InputSnap, InputSnaps};
|
||||
use crate::external;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Input {
|
||||
|
|
|
|||
|
|
@ -6,10 +6,8 @@
|
|||
clippy::unit_arg
|
||||
)]
|
||||
|
||||
mod blocker;
|
||||
pub mod completion;
|
||||
mod context;
|
||||
pub mod external;
|
||||
pub mod files;
|
||||
pub mod help;
|
||||
mod highlighter;
|
||||
|
|
@ -22,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(); }
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::path::{PathBuf, MAIN_SEPARATOR};
|
|||
|
||||
use tokio::fs;
|
||||
use yazi_config::popup::InputCfg;
|
||||
use yazi_shared::{emit, event::Exec, files::{File, FilesOp}, fs::Url};
|
||||
use yazi_shared::{emit, event::Exec, fs::{File, FilesOp}, fs::Url};
|
||||
|
||||
use crate::{input::Input, manager::Manager};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
use std::ffi::OsString;
|
||||
|
||||
use yazi_config::{popup::SelectCfg, OPEN};
|
||||
use yazi_scheduler::external;
|
||||
use yazi_shared::{event::Exec, MIME_DIR};
|
||||
|
||||
use crate::{external, manager::Manager, select::Select, tasks::Tasks};
|
||||
use crate::{manager::Manager, select::Select, tasks::Tasks};
|
||||
|
||||
pub struct Opt {
|
||||
interactive: bool,
|
||||
|
|
|
|||
|
|
@ -3,9 +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_shared::{emit, event::Exec, files::{File, FilesOp}, fs::{max_common_root, Url}, term::Term, Defer};
|
||||
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::{external::{self, ShellOpt}, input::Input, manager::Manager, Ctx, BLOCKER};
|
||||
use crate::{input::Input, manager::Manager, Ctx};
|
||||
|
||||
pub struct Opt {
|
||||
force: bool,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use std::collections::{BTreeMap, HashMap, HashSet};
|
||||
|
||||
use yazi_shared::{files::{File, FilesOp}, fs::Url};
|
||||
use yazi_shared::{fs::{File, FilesOp}, fs::Url};
|
||||
|
||||
use super::{Tabs, Watcher};
|
||||
use crate::{tab::{Folder, Tab}, tasks::Tasks};
|
||||
|
|
|
|||
|
|
@ -5,9 +5,10 @@ use notify::{event::{MetadataKind, ModifyKind}, EventKind, RecommendedWatcher, R
|
|||
use parking_lot::RwLock;
|
||||
use tokio::{fs, pin, sync::mpsc::{self, UnboundedReceiver}};
|
||||
use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt};
|
||||
use yazi_shared::{emit, files::{File, FilesOp}, fs::Url};
|
||||
use yazi_scheduler::external;
|
||||
use yazi_shared::{emit, fs::{File, FilesOp, Url}};
|
||||
|
||||
use crate::{external, files::Files};
|
||||
use crate::files::Files;
|
||||
|
||||
pub struct Watcher {
|
||||
watcher: RecommendedWatcher,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use tokio::{pin, task::JoinHandle};
|
|||
use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt};
|
||||
use yazi_adaptor::ADAPTOR;
|
||||
use yazi_config::MANAGER;
|
||||
use yazi_shared::{emit, event::{PreviewData, PreviewLock}, files::FilesOp, fs::{Cha, Url}, MimeKind, PeekError};
|
||||
use yazi_shared::{emit, event::{PreviewData, PreviewLock}, fs::{Cha, FilesOp, Url}, MimeKind, PeekError};
|
||||
|
||||
use super::Provider;
|
||||
use crate::{files::Files, manager::Manager, Highlighter};
|
||||
|
|
|
|||
|
|
@ -3,9 +3,10 @@ use std::path::Path;
|
|||
use tokio::fs;
|
||||
use yazi_adaptor::ADAPTOR;
|
||||
use yazi_config::{MANAGER, PREVIEW};
|
||||
use yazi_scheduler::external;
|
||||
use yazi_shared::{event::PreviewData, MimeKind, PeekError};
|
||||
|
||||
use crate::{external, Highlighter};
|
||||
use crate::Highlighter;
|
||||
|
||||
pub(super) struct Provider;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
use std::ffi::{OsStr, OsString};
|
||||
|
||||
use yazi_scheduler::external;
|
||||
use yazi_shared::event::Exec;
|
||||
|
||||
use crate::{external, tab::Tab};
|
||||
use crate::tab::Tab;
|
||||
|
||||
pub struct Opt<'a> {
|
||||
type_: &'a str,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use yazi_scheduler::{external::{self, FzfOpt, ZoxideOpt}, BLOCKER};
|
||||
use yazi_shared::{event::Exec, fs::ends_with_slash, Defer};
|
||||
|
||||
use crate::{external::{self, FzfOpt, ZoxideOpt}, tab::Tab, Ctx, BLOCKER};
|
||||
use crate::{tab::Tab, Ctx};
|
||||
|
||||
pub struct Opt {
|
||||
type_: OptType,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use yazi_shared::{emit, event::Exec, files::{File, FilesOp}, fs::{expand_path, Url}, Layer};
|
||||
use yazi_shared::{emit, event::Exec, fs::{File, FilesOp}, fs::{expand_path, Url}, Layer};
|
||||
|
||||
use crate::{manager::Manager, tab::Tab};
|
||||
|
||||
|
|
|
|||
|
|
@ -4,9 +4,10 @@ use anyhow::bail;
|
|||
use tokio::pin;
|
||||
use tokio_stream::{wrappers::UnboundedReceiverStream, StreamExt};
|
||||
use yazi_config::popup::InputCfg;
|
||||
use yazi_shared::{emit, event::Exec, files::FilesOp};
|
||||
use yazi_scheduler::external;
|
||||
use yazi_shared::{emit, event::Exec, fs::FilesOp};
|
||||
|
||||
use crate::{external, input::Input, manager::Manager, tab::Tab};
|
||||
use crate::{input::Input, manager::Manager, tab::Tab};
|
||||
|
||||
pub struct Opt {
|
||||
pub type_: OptType,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use ratatui::layout::Rect;
|
||||
use yazi_config::MANAGER;
|
||||
use yazi_shared::{emit, files::{File, FilesOp}, fs::Url};
|
||||
use yazi_shared::{emit, fs::{File, FilesOp}, fs::Url};
|
||||
|
||||
use crate::{files::Files, Step};
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::{borrow::Cow, collections::BTreeMap};
|
|||
|
||||
use anyhow::Result;
|
||||
use tokio::task::JoinHandle;
|
||||
use yazi_shared::{event::PreviewLock, files::File, fs::Url};
|
||||
use yazi_shared::{event::PreviewLock, fs::File, fs::Url};
|
||||
|
||||
use super::{Backstack, Config, Finder, Folder, Mode};
|
||||
use crate::preview::Preview;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
31
yazi-core/src/tasks/progress.rs
Normal file
31
yazi-core/src/tasks/progress.rs
Normal 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
|
||||
}
|
||||
}
|
||||
|
|
@ -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::{files::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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use crossterm::event::KeyEvent;
|
|||
use ratatui::{backend::Backend, prelude::Rect};
|
||||
use yazi_config::{keymap::Key, BOOT};
|
||||
use yazi_core::{input::InputMode, preview::COLLISION, Ctx};
|
||||
use yazi_shared::{emit, event::{Event, Exec}, files::FilesOp, term::Term, Layer};
|
||||
use yazi_shared::{emit, event::{Event, Exec}, fs::FilesOp, term::Term, Layer};
|
||||
|
||||
use crate::{Executor, Logs, Panic, Root, Signals};
|
||||
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ impl<'a, 'b> Active<'a, 'b> {
|
|||
fn file(
|
||||
&self,
|
||||
idx: usize,
|
||||
inner: &'a yazi_shared::files::File,
|
||||
inner: &'a yazi_shared::fs::File,
|
||||
folder: &'a yazi_core::tab::Folder,
|
||||
) -> mlua::Result<AnyUserData<'a>> {
|
||||
let ud = self.scope.create_any_userdata_ref(inner)?;
|
||||
|
|
|
|||
|
|
@ -6,10 +6,10 @@ use yazi_config::THEME;
|
|||
use super::{Range, Url};
|
||||
use crate::{layout::Style, LUA};
|
||||
|
||||
pub struct File(yazi_shared::files::File);
|
||||
pub struct File(yazi_shared::fs::File);
|
||||
|
||||
impl From<&yazi_shared::files::File> for File {
|
||||
fn from(value: &yazi_shared::files::File) -> Self { Self(value.clone()) }
|
||||
impl From<&yazi_shared::fs::File> for File {
|
||||
fn from(value: &yazi_shared::fs::File) -> Self { Self(value.clone()) }
|
||||
}
|
||||
|
||||
impl UserData for File {
|
||||
|
|
@ -47,7 +47,7 @@ impl Files {
|
|||
});
|
||||
})?;
|
||||
|
||||
LUA.register_userdata_type::<yazi_shared::files::File>(|reg| {
|
||||
LUA.register_userdata_type::<yazi_shared::fs::File>(|reg| {
|
||||
reg.add_field_method_get("url", |_, me| Ok(Url::from(&me.url)));
|
||||
reg.add_field_method_get("link_to", |_, me| Ok(me.link_to().map(Url::from)));
|
||||
reg.add_field_method_get("is_link", |_, me| Ok(me.is_link()));
|
||||
|
|
@ -87,7 +87,7 @@ impl Files {
|
|||
Ok(me.url.file_name().map(|n| n.to_string_lossy().to_string()))
|
||||
});
|
||||
reg.add_function("size", |_, me: AnyUserData| {
|
||||
let file = me.borrow::<yazi_shared::files::File>()?;
|
||||
let file = me.borrow::<yazi_shared::fs::File>()?;
|
||||
if !file.is_dir() {
|
||||
return Ok(Some(file.len));
|
||||
}
|
||||
|
|
@ -97,7 +97,7 @@ impl Files {
|
|||
});
|
||||
reg.add_function("mime", |_, me: AnyUserData| {
|
||||
let manager = me.named_user_value::<UserDataRef<yazi_core::manager::Manager>>("manager")?;
|
||||
let file = me.borrow::<yazi_shared::files::File>()?;
|
||||
let file = me.borrow::<yazi_shared::fs::File>()?;
|
||||
Ok(manager.mimetype.get(&file.url).cloned())
|
||||
});
|
||||
reg.add_function("prefix", |_, me: AnyUserData| {
|
||||
|
|
@ -106,7 +106,7 @@ impl Files {
|
|||
return Ok(None);
|
||||
}
|
||||
|
||||
let file = me.borrow::<yazi_shared::files::File>()?;
|
||||
let file = me.borrow::<yazi_shared::fs::File>()?;
|
||||
let mut p = file.url.strip_prefix(&folder.cwd).unwrap_or(&file.url).components();
|
||||
p.next_back();
|
||||
Ok(Some(p.as_path().to_string_lossy().to_string()))
|
||||
|
|
@ -122,7 +122,7 @@ impl Files {
|
|||
});
|
||||
reg.add_function("style", |_, me: AnyUserData| {
|
||||
let manager = me.named_user_value::<UserDataRef<yazi_core::manager::Manager>>("manager")?;
|
||||
let file = me.borrow::<yazi_shared::files::File>()?;
|
||||
let file = me.borrow::<yazi_shared::fs::File>()?;
|
||||
let mime = manager.mimetype.get(&file.url);
|
||||
Ok(
|
||||
THEME
|
||||
|
|
@ -134,12 +134,12 @@ impl Files {
|
|||
});
|
||||
reg.add_function("is_hovered", |_, me: AnyUserData| {
|
||||
let folder = me.named_user_value::<UserDataRef<yazi_core::tab::Folder>>("folder")?;
|
||||
let file = me.borrow::<yazi_shared::files::File>()?;
|
||||
let file = me.borrow::<yazi_shared::fs::File>()?;
|
||||
Ok(matches!(folder.hovered(), Some(f) if f.url == file.url))
|
||||
});
|
||||
reg.add_function("is_yanked", |_, me: AnyUserData| {
|
||||
let manager = me.named_user_value::<UserDataRef<yazi_core::manager::Manager>>("manager")?;
|
||||
let file = me.borrow::<yazi_shared::files::File>()?;
|
||||
let file = me.borrow::<yazi_shared::fs::File>()?;
|
||||
Ok(if !manager.yanked.1.contains(&file.url) {
|
||||
0u8
|
||||
} else if manager.yanked.0 {
|
||||
|
|
@ -151,7 +151,7 @@ impl Files {
|
|||
reg.add_function("is_selected", |_, me: AnyUserData| {
|
||||
let manager = me.named_user_value::<UserDataRef<yazi_core::manager::Manager>>("manager")?;
|
||||
let folder = me.named_user_value::<UserDataRef<yazi_core::tab::Folder>>("folder")?;
|
||||
let file = me.borrow::<yazi_shared::files::File>()?;
|
||||
let file = me.borrow::<yazi_shared::fs::File>()?;
|
||||
|
||||
let selected = folder.files.is_selected(&file.url);
|
||||
Ok(if !manager.active().mode.is_visual() {
|
||||
|
|
@ -167,7 +167,7 @@ impl Files {
|
|||
return Ok(None);
|
||||
};
|
||||
|
||||
let file = me.borrow::<yazi_shared::files::File>()?;
|
||||
let file = me.borrow::<yazi_shared::fs::File>()?;
|
||||
if let Some(idx) = finder.matched_idx(&file.url) {
|
||||
return Some(
|
||||
lua.create_sequence_from([idx.into_lua(lua)?, finder.matched().len().into_lua(lua)?]),
|
||||
|
|
@ -182,7 +182,7 @@ impl Files {
|
|||
return Ok(None);
|
||||
};
|
||||
|
||||
let file = me.borrow::<yazi_shared::files::File>()?;
|
||||
let file = me.borrow::<yazi_shared::fs::File>()?;
|
||||
let Some(h) = file.name().and_then(|n| finder.highlighted(n)) else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
|
|
|||
32
yazi-scheduler/Cargo.toml
Normal file
32
yazi-scheduler/Cargo.toml
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
[package]
|
||||
name = "yazi-scheduler"
|
||||
version = "0.1.5"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
authors = [ "sxyazi <sxyazi@gmail.com>" ]
|
||||
description = "Yazi task scheduler"
|
||||
homepage = "https://yazi-rs.github.io"
|
||||
repository = "https://github.com/sxyazi/yazi"
|
||||
|
||||
[dependencies]
|
||||
yazi-adaptor = { path = "../yazi-adaptor", version = "0.1.5" }
|
||||
yazi-config = { path = "../yazi-config", version = "0.1.5" }
|
||||
yazi-shared = { path = "../yazi-shared", version = "0.1.5" }
|
||||
|
||||
# External dependencies
|
||||
anyhow = "^1"
|
||||
async-channel = "^1"
|
||||
futures = "^0"
|
||||
libc = "^0"
|
||||
parking_lot = "^0"
|
||||
regex = "^1"
|
||||
serde = "^1"
|
||||
serde_json = "^1"
|
||||
tokio = { version = "^1", features = [ "parking_lot", "rt-multi-thread" ] }
|
||||
trash = "^3"
|
||||
|
||||
# Logging
|
||||
tracing = { version = "^0", features = [ "max_level_debug", "release_max_level_warn" ] }
|
||||
|
||||
[target."cfg(windows)".dependencies]
|
||||
clipboard-win = "^4"
|
||||
|
|
@ -2,7 +2,7 @@ use std::process::Stdio;
|
|||
|
||||
use anyhow::Result;
|
||||
use tokio::{io::{AsyncBufReadExt, BufReader}, process::Command, sync::mpsc::{self, UnboundedReceiver}};
|
||||
use yazi_shared::{files::File, fs::Url};
|
||||
use yazi_shared::fs::{File, Url};
|
||||
|
||||
pub struct FdOpt {
|
||||
pub cwd: Url,
|
||||
|
|
@ -2,7 +2,7 @@ use std::process::Stdio;
|
|||
|
||||
use anyhow::Result;
|
||||
use tokio::{io::{AsyncBufReadExt, BufReader}, process::Command, sync::mpsc::{self, UnboundedReceiver}};
|
||||
use yazi_shared::{files::File, fs::Url};
|
||||
use yazi_shared::fs::{File, Url};
|
||||
|
||||
pub struct RgOpt {
|
||||
pub cwd: Url,
|
||||
15
yazi-scheduler/src/lib.rs
Normal file
15
yazi-scheduler/src/lib.rs
Normal file
|
|
@ -0,0 +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(); }
|
||||
|
|
@ -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,
|
||||
|
|
@ -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);
|
||||
|
||||
|
|
@ -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>,
|
||||
|
|
@ -5,9 +5,9 @@ use parking_lot::Mutex;
|
|||
use tokio::{fs, sync::mpsc};
|
||||
use yazi_adaptor::Image;
|
||||
use yazi_config::PREVIEW;
|
||||
use yazi_shared::{emit, files::FilesOp, fs::{calculate_size, Url}, Throttle};
|
||||
use yazi_shared::{emit, fs::{calculate_size, FilesOp, Url}, Throttle};
|
||||
|
||||
use crate::{external, tasks::TaskOp};
|
||||
use crate::{external, TaskOp};
|
||||
|
||||
pub(crate) struct Precache {
|
||||
tx: async_channel::Sender<PrecacheOp>,
|
||||
|
|
@ -3,7 +3,7 @@ use std::{ffi::OsString, mem};
|
|||
use anyhow::Result;
|
||||
use tokio::{io::{AsyncBufReadExt, BufReader}, select, sync::{mpsc, oneshot}};
|
||||
|
||||
use crate::{external::{self, ShellOpt}, tasks::TaskOp, Ctx, BLOCKER};
|
||||
use crate::{external::{self, ShellOpt}, Scheduler, TaskOp, BLOCKER};
|
||||
|
||||
pub(crate) struct Process {
|
||||
sch: mpsc::UnboundedSender<TaskOp>,
|
||||
|
|
@ -37,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) => {
|
||||
|
|
@ -49,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 {
|
||||
|
|
@ -4,7 +4,7 @@ use crossterm::event::KeyEvent;
|
|||
use tokio::sync::{mpsc::UnboundedSender, oneshot};
|
||||
|
||||
use super::Exec;
|
||||
use crate::{files::FilesOp, fs::{Cha, Url}, term::Term, Layer, RoCell};
|
||||
use crate::{fs::{Cha, FilesOp, Url}, term::Term, Layer, RoCell};
|
||||
|
||||
static TX: RoCell<UnboundedSender<Event>> = RoCell::new();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
mod file;
|
||||
mod op;
|
||||
|
||||
pub use file::*;
|
||||
pub use op::*;
|
||||
|
|
@ -1,9 +1,13 @@
|
|||
mod cha;
|
||||
mod file;
|
||||
mod fns;
|
||||
mod op;
|
||||
mod path;
|
||||
mod url;
|
||||
|
||||
pub use cha::*;
|
||||
pub use file::*;
|
||||
pub use fns::*;
|
||||
pub use op::*;
|
||||
pub use path::*;
|
||||
pub use url::*;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ mod defer;
|
|||
mod env;
|
||||
mod errors;
|
||||
pub mod event;
|
||||
pub mod files;
|
||||
pub mod fs;
|
||||
mod layer;
|
||||
mod mime;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue