mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
feat: check and refresh the file list when the terminal gains focus (#3561)
This commit is contained in:
parent
41e5717930
commit
0c8c973e6c
18 changed files with 95 additions and 69 deletions
|
|
@ -16,6 +16,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/):
|
||||||
|
|
||||||
- Tree view for the preset archive previewer ([#3525])
|
- Tree view for the preset archive previewer ([#3525])
|
||||||
- Support compressed tarballs (`.tar.gz`, `.tar.bz2`, etc.) in the preset archive previewer ([#3518])
|
- Support compressed tarballs (`.tar.gz`, `.tar.bz2`, etc.) in the preset archive previewer ([#3518])
|
||||||
|
- Check and refresh the file list when the terminal gains focus ([#3561])
|
||||||
- New `Path.os()` API creates an OS-native `Path` ([#3541])
|
- New `Path.os()` API creates an OS-native `Path` ([#3541])
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
@ -1601,3 +1602,4 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/):
|
||||||
[#3532]: https://github.com/sxyazi/yazi/pull/3532
|
[#3532]: https://github.com/sxyazi/yazi/pull/3532
|
||||||
[#3540]: https://github.com/sxyazi/yazi/pull/3540
|
[#3540]: https://github.com/sxyazi/yazi/pull/3540
|
||||||
[#3541]: https://github.com/sxyazi/yazi/pull/3541
|
[#3541]: https://github.com/sxyazi/yazi/pull/3541
|
||||||
|
[#3561]: https://github.com/sxyazi/yazi/pull/3561
|
||||||
|
|
|
||||||
|
|
@ -21,11 +21,12 @@ impl Actions {
|
||||||
writeln!(s, " Version: {}", Self::process_output("ya", "--version"))?;
|
writeln!(s, " Version: {}", Self::process_output("ya", "--version"))?;
|
||||||
|
|
||||||
writeln!(s, "\nConfig")?;
|
writeln!(s, "\nConfig")?;
|
||||||
writeln!(s, " Yazi : {}", Self::config_state("yazi"))?;
|
writeln!(s, " Init : {}", Self::config_state("init.lua"))?;
|
||||||
writeln!(s, " Keymap : {}", Self::config_state("keymap"))?;
|
writeln!(s, " Yazi : {}", Self::config_state("yazi.toml"))?;
|
||||||
writeln!(s, " Theme : {}", Self::config_state("theme"))?;
|
writeln!(s, " Keymap : {}", Self::config_state("keymap.toml"))?;
|
||||||
writeln!(s, " VFS : {}", Self::config_state("vfs"))?;
|
writeln!(s, " Theme : {}", Self::config_state("theme.toml"))?;
|
||||||
writeln!(s, " Package : {}", Self::config_state("package"))?;
|
writeln!(s, " VFS : {}", Self::config_state("vfs.toml"))?;
|
||||||
|
writeln!(s, " Package : {}", Self::config_state("package.toml"))?;
|
||||||
writeln!(s, " Dark/light flavor: {:?} / {:?}", THEME.flavor.dark, THEME.flavor.light)?;
|
writeln!(s, " Dark/light flavor: {:?} / {:?}", THEME.flavor.dark, THEME.flavor.light)?;
|
||||||
|
|
||||||
writeln!(s, "\nEmulator")?;
|
writeln!(s, "\nEmulator")?;
|
||||||
|
|
@ -125,7 +126,7 @@ impl Actions {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn config_state(name: &str) -> String {
|
fn config_state(name: &str) -> String {
|
||||||
let p = Xdg::config_dir().join(format!("{name}.toml"));
|
let p = Xdg::config_dir().join(name);
|
||||||
match std::fs::read_to_string(&p) {
|
match std::fs::read_to_string(&p) {
|
||||||
Ok(s) if s.is_empty() => format!("{} (empty)", p.display()),
|
Ok(s) if s.is_empty() => format!("{} (empty)", p.display()),
|
||||||
Ok(s) if s.trim().is_empty() => format!("{} (whitespaces)", p.display()),
|
Ok(s) if s.trim().is_empty() => format!("{} (whitespaces)", p.display()),
|
||||||
|
|
|
||||||
15
yazi-fm/src/app/commands/focus.rs
Normal file
15
yazi-fm/src/app/commands/focus.rs
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
use anyhow::Result;
|
||||||
|
use yazi_actor::Ctx;
|
||||||
|
use yazi_macro::act;
|
||||||
|
use yazi_parser::VoidOpt;
|
||||||
|
use yazi_shared::data::Data;
|
||||||
|
|
||||||
|
use crate::app::App;
|
||||||
|
|
||||||
|
impl App {
|
||||||
|
pub fn focus(&mut self, _: VoidOpt) -> Result<Data> {
|
||||||
|
let cx = &mut Ctx::active(&mut self.core);
|
||||||
|
|
||||||
|
act!(mgr:refresh, cx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,7 @@ yazi_macro::mod_flat!(
|
||||||
accept_payload
|
accept_payload
|
||||||
bootstrap
|
bootstrap
|
||||||
deprecate
|
deprecate
|
||||||
|
focus
|
||||||
mouse
|
mouse
|
||||||
notify
|
notify
|
||||||
plugin
|
plugin
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ impl<'a> Dispatcher<'a> {
|
||||||
Event::Key(key) => self.dispatch_key(key),
|
Event::Key(key) => self.dispatch_key(key),
|
||||||
Event::Mouse(mouse) => act!(mouse, self.app, mouse),
|
Event::Mouse(mouse) => act!(mouse, self.app, mouse),
|
||||||
Event::Resize => act!(resize, self.app),
|
Event::Resize => act!(resize, self.app),
|
||||||
|
Event::Focus => act!(focus, self.app),
|
||||||
Event::Paste(str) => self.dispatch_paste(str),
|
Event::Paste(str) => self.dispatch_paste(str),
|
||||||
Event::Quit(opt) => act!(quit, self.app, opt),
|
Event::Quit(opt) => act!(quit, self.app, opt),
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -64,8 +64,9 @@ impl Signals {
|
||||||
Event::Mouse(mouse).emit();
|
Event::Mouse(mouse).emit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CrosstermEvent::Paste(str) => Event::Paste(str).emit(),
|
|
||||||
CrosstermEvent::Resize(..) => Event::Resize.emit(),
|
CrosstermEvent::Resize(..) => Event::Resize.emit(),
|
||||||
|
CrosstermEvent::FocusGained => Event::Focus.emit(),
|
||||||
|
CrosstermEvent::Paste(str) => Event::Paste(str).emit(),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use std::{io, ops::{Deref, DerefMut}, sync::atomic::{AtomicBool, Ordering}};
|
use std::{io, ops::{Deref, DerefMut}, sync::atomic::{AtomicBool, Ordering}};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use crossterm::{event::{DisableBracketedPaste, DisableMouseCapture, EnableBracketedPaste, EnableMouseCapture, KeyboardEnhancementFlags, PopKeyboardEnhancementFlags, PushKeyboardEnhancementFlags}, execute, queue, style::Print, terminal::{EnterAlternateScreen, LeaveAlternateScreen, SetTitle, disable_raw_mode, enable_raw_mode}};
|
use crossterm::{event::{DisableBracketedPaste, DisableFocusChange, DisableMouseCapture, EnableBracketedPaste, EnableFocusChange, EnableMouseCapture, KeyboardEnhancementFlags, PopKeyboardEnhancementFlags, PushKeyboardEnhancementFlags}, execute, queue, style::Print, terminal::{EnterAlternateScreen, LeaveAlternateScreen, SetTitle, disable_raw_mode, enable_raw_mode}};
|
||||||
use ratatui::{CompletedFrame, Frame, Terminal, backend::CrosstermBackend, buffer::Buffer, layout::Rect};
|
use ratatui::{CompletedFrame, Frame, Terminal, backend::CrosstermBackend, buffer::Buffer, layout::Rect};
|
||||||
use yazi_adapter::{Emulator, Mux, TMUX};
|
use yazi_adapter::{Emulator, Mux, TMUX};
|
||||||
use yazi_config::{THEME, YAZI};
|
use yazi_config::{THEME, YAZI};
|
||||||
|
|
@ -40,6 +40,7 @@ impl Term {
|
||||||
yazi_term::If(TMUX.get(), EnterAlternateScreen),
|
yazi_term::If(TMUX.get(), EnterAlternateScreen),
|
||||||
yazi_term::SetBackground(true, THEME.app.bg_color()), // Set app background
|
yazi_term::SetBackground(true, THEME.app.bg_color()), // Set app background
|
||||||
EnableBracketedPaste,
|
EnableBracketedPaste,
|
||||||
|
EnableFocusChange,
|
||||||
yazi_term::If(!YAZI.mgr.mouse_events.get().is_empty(), EnableMouseCapture),
|
yazi_term::If(!YAZI.mgr.mouse_events.get().is_empty(), EnableMouseCapture),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
|
@ -81,6 +82,7 @@ impl Term {
|
||||||
TTY.writer(),
|
TTY.writer(),
|
||||||
yazi_term::If(!YAZI.mgr.mouse_events.get().is_empty(), DisableMouseCapture),
|
yazi_term::If(!YAZI.mgr.mouse_events.get().is_empty(), DisableMouseCapture),
|
||||||
yazi_term::RestoreCursor,
|
yazi_term::RestoreCursor,
|
||||||
|
DisableFocusChange,
|
||||||
DisableBracketedPaste,
|
DisableBracketedPaste,
|
||||||
LeaveAlternateScreen,
|
LeaveAlternateScreen,
|
||||||
)?;
|
)?;
|
||||||
|
|
@ -103,6 +105,7 @@ impl Term {
|
||||||
yazi_term::If(!YAZI.mgr.mouse_events.get().is_empty(), DisableMouseCapture),
|
yazi_term::If(!YAZI.mgr.mouse_events.get().is_empty(), DisableMouseCapture),
|
||||||
yazi_term::SetBackground(false, THEME.app.bg_color()),
|
yazi_term::SetBackground(false, THEME.app.bg_color()),
|
||||||
yazi_term::RestoreCursor,
|
yazi_term::RestoreCursor,
|
||||||
|
DisableFocusChange,
|
||||||
DisableBracketedPaste,
|
DisableBracketedPaste,
|
||||||
LeaveAlternateScreen,
|
LeaveAlternateScreen,
|
||||||
crossterm::cursor::Show
|
crossterm::cursor::Show
|
||||||
|
|
|
||||||
|
|
@ -455,6 +455,7 @@ pub(crate) enum FileOutUpload {
|
||||||
Deform(String),
|
Deform(String),
|
||||||
Succ,
|
Succ,
|
||||||
Fail(String),
|
Fail(String),
|
||||||
|
Clean,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<anyhow::Error> for FileOutUpload {
|
impl From<anyhow::Error> for FileOutUpload {
|
||||||
|
|
@ -481,6 +482,9 @@ impl FileOutUpload {
|
||||||
prog.collected = Some(false);
|
prog.collected = Some(false);
|
||||||
task.log(reason);
|
task.log(reason);
|
||||||
}
|
}
|
||||||
|
Self::Clean => {
|
||||||
|
prog.cleaned = Some(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -321,6 +321,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>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<FileProgUpload> for TaskSummary {
|
impl From<FileProgUpload> for TaskSummary {
|
||||||
|
|
@ -340,14 +341,16 @@ impl FileProgUpload {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn running(self) -> bool {
|
pub fn running(self) -> bool {
|
||||||
self.collected.is_none() || self.success_files + self.failed_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.cooked() }
|
pub fn success(self) -> bool { self.cleaned == Some(true) && self.cooked() }
|
||||||
|
|
||||||
pub fn failed(self) -> bool { self.collected == Some(false) }
|
pub fn failed(self) -> bool { self.cleaned == Some(false) || self.collected == Some(false) }
|
||||||
|
|
||||||
pub fn cleaned(self) -> Option<bool> { None }
|
pub fn cleaned(self) -> Option<bool> { self.cleaned }
|
||||||
|
|
||||||
pub fn percent(self) -> Option<f32> {
|
pub fn percent(self) -> Option<f32> {
|
||||||
Some(if self.success() {
|
Some(if self.success() {
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ use yazi_fs::ok_or_not_found;
|
||||||
use yazi_proxy::TasksProxy;
|
use yazi_proxy::TasksProxy;
|
||||||
use yazi_vfs::provider;
|
use yazi_vfs::provider;
|
||||||
|
|
||||||
use crate::{Ongoing, TaskOp, TaskOps, file::{FileOutCopy, FileOutCut, FileOutDelete, FileOutDownload, FileOutTrash}, hook::{HookInOutCopy, HookInOutCut, HookInOutDelete, HookInOutDownload, HookInOutTrash}};
|
use crate::{Ongoing, TaskOp, TaskOps, file::{FileOutCopy, FileOutCut, FileOutDelete, FileOutDownload, FileOutTrash, FileOutUpload}, hook::{HookInDelete, HookInDownload, HookInOutCopy, HookInOutCut, HookInTrash, HookInUpload}};
|
||||||
|
|
||||||
pub(crate) struct Hook {
|
pub(crate) struct Hook {
|
||||||
ops: TaskOps,
|
ops: TaskOps,
|
||||||
|
|
@ -41,7 +41,7 @@ impl Hook {
|
||||||
self.ops.out(task.id, FileOutCopy::Clean);
|
self.ops.out(task.id, FileOutCopy::Clean);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn delete(&self, task: HookInOutDelete) {
|
pub(crate) async fn delete(&self, task: HookInDelete) {
|
||||||
if !self.ongoing.lock().intact(task.id) {
|
if !self.ongoing.lock().intact(task.id) {
|
||||||
return self.ops.out(task.id, FileOutDelete::Clean(Ok(())));
|
return self.ops.out(task.id, FileOutDelete::Clean(Ok(())));
|
||||||
}
|
}
|
||||||
|
|
@ -53,7 +53,7 @@ impl Hook {
|
||||||
self.ops.out(task.id, FileOutDelete::Clean(result));
|
self.ops.out(task.id, FileOutDelete::Clean(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn trash(&self, task: HookInOutTrash) {
|
pub(crate) async fn trash(&self, task: HookInTrash) {
|
||||||
let intact = self.ongoing.lock().intact(task.id);
|
let intact = self.ongoing.lock().intact(task.id);
|
||||||
if intact {
|
if intact {
|
||||||
TasksProxy::update_succeed([&task.target]);
|
TasksProxy::update_succeed([&task.target]);
|
||||||
|
|
@ -62,7 +62,15 @@ impl Hook {
|
||||||
self.ops.out(task.id, FileOutTrash::Clean);
|
self.ops.out(task.id, FileOutTrash::Clean);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn download(&self, task: HookInOutDownload) {
|
pub(crate) async fn download(&self, task: HookInDownload) {
|
||||||
self.ops.out(task.id, FileOutDownload::Clean);
|
self.ops.out(task.id, FileOutDownload::Clean);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn upload(&self, task: HookInUpload) {
|
||||||
|
let intact = self.ongoing.lock().intact(task.id);
|
||||||
|
if intact {
|
||||||
|
TasksProxy::update_succeed([task.target]);
|
||||||
|
}
|
||||||
|
self.ops.out(task.id, FileOutUpload::Clean);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,44 +48,27 @@ impl HookInOutCut {
|
||||||
|
|
||||||
// --- Delete
|
// --- Delete
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct HookInOutDelete {
|
pub(crate) struct HookInDelete {
|
||||||
pub(crate) id: Id,
|
pub(crate) id: Id,
|
||||||
pub(crate) target: UrlBuf,
|
pub(crate) target: UrlBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HookInOutDelete {
|
|
||||||
pub(crate) fn reduce(self, task: &mut Task) {
|
|
||||||
if let TaskProg::FileDelete(_) = &task.prog {
|
|
||||||
task.hook = Some(self.into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Trash
|
// --- Trash
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct HookInOutTrash {
|
pub(crate) struct HookInTrash {
|
||||||
pub(crate) id: Id,
|
pub(crate) id: Id,
|
||||||
pub(crate) target: UrlBuf,
|
pub(crate) target: UrlBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HookInOutTrash {
|
|
||||||
pub(crate) fn reduce(self, task: &mut Task) {
|
|
||||||
if let TaskProg::FileTrash(_) = &task.prog {
|
|
||||||
task.hook = Some(self.into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Download
|
// --- Download
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct HookInOutDownload {
|
pub(crate) struct HookInDownload {
|
||||||
pub(crate) id: Id,
|
pub(crate) id: Id,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HookInOutDownload {
|
// --- Upload
|
||||||
pub(crate) fn reduce(self, task: &mut Task) {
|
#[derive(Debug)]
|
||||||
if let TaskProg::FileDownload(_) = &task.prog {
|
pub(crate) struct HookInUpload {
|
||||||
task.hook = Some(self.into());
|
pub(crate) id: Id,
|
||||||
}
|
pub(crate) target: UrlBuf,
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use yazi_shared::Id;
|
use yazi_shared::Id;
|
||||||
|
|
||||||
use crate::{file::{FileInCopy, FileInCut, FileInDelete, FileInDownload, FileInHardlink, FileInLink, FileInTrash, FileInUpload}, hook::{HookInOutCopy, HookInOutCut, HookInOutDelete, HookInOutDownload, HookInOutTrash}, impl_from_in, plugin::PluginInEntry, prework::{PreworkInFetch, PreworkInLoad, PreworkInSize}, process::{ProcessInBg, ProcessInBlock, ProcessInOrphan}};
|
use crate::{file::{FileInCopy, FileInCut, FileInDelete, FileInDownload, FileInHardlink, FileInLink, FileInTrash, FileInUpload}, hook::{HookInDelete, HookInDownload, HookInOutCopy, HookInOutCut, HookInTrash, HookInUpload}, impl_from_in, plugin::PluginInEntry, prework::{PreworkInFetch, PreworkInLoad, PreworkInSize}, process::{ProcessInBg, ProcessInBlock, ProcessInOrphan}};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) enum TaskIn {
|
pub(crate) enum TaskIn {
|
||||||
|
|
@ -26,9 +26,10 @@ pub(crate) enum TaskIn {
|
||||||
// Hook
|
// Hook
|
||||||
HookCopy(HookInOutCopy),
|
HookCopy(HookInOutCopy),
|
||||||
HookCut(HookInOutCut),
|
HookCut(HookInOutCut),
|
||||||
HookDelete(HookInOutDelete),
|
HookDelete(HookInDelete),
|
||||||
HookTrash(HookInOutTrash),
|
HookTrash(HookInTrash),
|
||||||
HookDownload(HookInOutDownload),
|
HookDownload(HookInDownload),
|
||||||
|
HookUpload(HookInUpload),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_from_in! {
|
impl_from_in! {
|
||||||
|
|
@ -41,7 +42,7 @@ impl_from_in! {
|
||||||
// Process
|
// Process
|
||||||
ProcessBlock(ProcessInBlock), ProcessOrphan(ProcessInOrphan), ProcessBg(ProcessInBg),
|
ProcessBlock(ProcessInBlock), ProcessOrphan(ProcessInOrphan), ProcessBg(ProcessInBg),
|
||||||
// Hook
|
// Hook
|
||||||
HookCopy(HookInOutCopy), HookCut(HookInOutCut), HookDelete(HookInOutDelete), HookTrash(HookInOutTrash), HookDownload(HookInOutDownload),
|
HookCopy(HookInOutCopy), HookCut(HookInOutCut), HookDelete(HookInDelete), HookTrash(HookInTrash), HookDownload(HookInDownload), HookUpload(HookInUpload),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TaskIn {
|
impl TaskIn {
|
||||||
|
|
@ -72,6 +73,7 @@ impl TaskIn {
|
||||||
Self::HookDelete(r#in) => r#in.id,
|
Self::HookDelete(r#in) => r#in.id,
|
||||||
Self::HookTrash(r#in) => r#in.id,
|
Self::HookTrash(r#in) => r#in.id,
|
||||||
Self::HookDownload(r#in) => r#in.id,
|
Self::HookDownload(r#in) => r#in.id,
|
||||||
|
Self::HookUpload(r#in) => r#in.id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -102,6 +104,7 @@ impl TaskIn {
|
||||||
Self::HookDelete(_) => true,
|
Self::HookDelete(_) => true,
|
||||||
Self::HookTrash(_) => true,
|
Self::HookTrash(_) => true,
|
||||||
Self::HookDownload(_) => true,
|
Self::HookDownload(_) => true,
|
||||||
|
Self::HookUpload(_) => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{Task, file::{FileOutCopy, FileOutCopyDo, FileOutCut, FileOutCutDo, FileOutDelete, FileOutDeleteDo, FileOutDownload, FileOutDownloadDo, FileOutHardlink, FileOutHardlinkDo, FileOutLink, FileOutTrash, FileOutUpload, FileOutUploadDo}, hook::{HookInOutCopy, HookInOutCut, HookInOutDelete, HookInOutDownload, HookInOutTrash}, impl_from_out, plugin::PluginOutEntry, prework::{PreworkOutFetch, PreworkOutLoad, PreworkOutSize}, process::{ProcessOutBg, ProcessOutBlock, ProcessOutOrphan}};
|
use crate::{Task, file::{FileOutCopy, FileOutCopyDo, FileOutCut, FileOutCutDo, FileOutDelete, FileOutDeleteDo, FileOutDownload, FileOutDownloadDo, FileOutHardlink, FileOutHardlinkDo, FileOutLink, FileOutTrash, FileOutUpload, FileOutUploadDo}, hook::{HookInOutCopy, HookInOutCut}, impl_from_out, plugin::PluginOutEntry, prework::{PreworkOutFetch, PreworkOutLoad, PreworkOutSize}, process::{ProcessOutBg, ProcessOutBlock, ProcessOutOrphan}};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(super) enum TaskOut {
|
pub(super) enum TaskOut {
|
||||||
|
|
@ -30,9 +30,6 @@ pub(super) enum TaskOut {
|
||||||
// Hook
|
// Hook
|
||||||
HookCopy(HookInOutCopy),
|
HookCopy(HookInOutCopy),
|
||||||
HookCut(HookInOutCut),
|
HookCut(HookInOutCut),
|
||||||
HookDelete(HookInOutDelete),
|
|
||||||
HookTrash(HookInOutTrash),
|
|
||||||
HookDownload(HookInOutDownload),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_from_out! {
|
impl_from_out! {
|
||||||
|
|
@ -45,7 +42,7 @@ impl_from_out! {
|
||||||
// Process
|
// Process
|
||||||
ProcessBlock(ProcessOutBlock), ProcessOrphan(ProcessOutOrphan), ProcessBg(ProcessOutBg),
|
ProcessBlock(ProcessOutBlock), ProcessOrphan(ProcessOutOrphan), ProcessBg(ProcessOutBg),
|
||||||
// Hook
|
// Hook
|
||||||
HookCopy(HookInOutCopy), HookCut(HookInOutCut), HookDelete(HookInOutDelete), HookTrash(HookInOutTrash), HookDownload(HookInOutDownload),
|
HookCopy(HookInOutCopy), HookCut(HookInOutCut),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TaskOut {
|
impl TaskOut {
|
||||||
|
|
@ -79,9 +76,6 @@ impl TaskOut {
|
||||||
// Hook
|
// Hook
|
||||||
Self::HookCopy(out) => out.reduce(task),
|
Self::HookCopy(out) => out.reduce(task),
|
||||||
Self::HookCut(out) => out.reduce(task),
|
Self::HookCut(out) => out.reduce(task),
|
||||||
Self::HookDelete(out) => out.reduce(task),
|
|
||||||
Self::HookTrash(out) => out.reduce(task),
|
|
||||||
Self::HookDownload(out) => out.reduce(task),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ impl Runner {
|
||||||
TaskIn::HookDelete(r#in) => Ok(self.hook.delete(r#in).await),
|
TaskIn::HookDelete(r#in) => Ok(self.hook.delete(r#in).await),
|
||||||
TaskIn::HookTrash(r#in) => Ok(self.hook.trash(r#in).await),
|
TaskIn::HookTrash(r#in) => Ok(self.hook.trash(r#in).await),
|
||||||
TaskIn::HookDownload(r#in) => Ok(self.hook.download(r#in).await),
|
TaskIn::HookDownload(r#in) => Ok(self.hook.download(r#in).await),
|
||||||
|
TaskIn::HookUpload(r#in) => Ok(self.hook.upload(r#in).await),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -69,6 +70,7 @@ impl Runner {
|
||||||
TaskIn::HookDelete(_in) => unreachable!(),
|
TaskIn::HookDelete(_in) => unreachable!(),
|
||||||
TaskIn::HookTrash(_in) => unreachable!(),
|
TaskIn::HookTrash(_in) => unreachable!(),
|
||||||
TaskIn::HookDownload(_in) => unreachable!(),
|
TaskIn::HookDownload(_in) => unreachable!(),
|
||||||
|
TaskIn::HookUpload(_in) => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ use yazi_parser::{app::PluginOpt, tasks::ProcessOpenOpt};
|
||||||
use yazi_shared::{CompletionToken, Id, Throttle, url::{UrlBuf, UrlLike}};
|
use yazi_shared::{CompletionToken, Id, Throttle, url::{UrlBuf, UrlLike}};
|
||||||
|
|
||||||
use super::{Ongoing, TaskOp};
|
use super::{Ongoing, TaskOp};
|
||||||
use crate::{HIGH, LOW, NORMAL, Runner, TaskIn, TaskOps, file::{File, FileInCopy, FileInCut, FileInDelete, FileInDownload, FileInHardlink, FileInLink, FileInTrash, FileInUpload, FileOutCopy, FileOutCut, FileOutDownload, FileOutHardlink, FileOutUpload, FileProgCopy, FileProgCut, FileProgDelete, FileProgDownload, FileProgHardlink, FileProgLink, FileProgTrash, FileProgUpload}, hook::{Hook, HookInOutDelete, HookInOutDownload, HookInOutTrash}, plugin::{Plugin, PluginInEntry, PluginProgEntry}, prework::{Prework, PreworkInFetch, PreworkInLoad, PreworkInSize, PreworkProgFetch, PreworkProgLoad, PreworkProgSize}, process::{Process, ProcessInBg, ProcessInBlock, ProcessInOrphan, ProcessProgBg, ProcessProgBlock, ProcessProgOrphan}};
|
use crate::{HIGH, LOW, NORMAL, Runner, TaskIn, TaskOps, file::{File, FileInCopy, FileInCut, FileInDelete, FileInDownload, FileInHardlink, FileInLink, FileInTrash, FileInUpload, FileOutCopy, FileOutCut, FileOutDownload, FileOutHardlink, FileOutUpload, FileProgCopy, FileProgCut, FileProgDelete, FileProgDownload, FileProgHardlink, FileProgLink, FileProgTrash, FileProgUpload}, hook::{Hook, HookInDelete, HookInDownload, HookInTrash, HookInUpload}, plugin::{Plugin, PluginInEntry, PluginProgEntry}, prework::{Prework, PreworkInFetch, PreworkInLoad, PreworkInSize, PreworkProgFetch, PreworkProgLoad, PreworkProgSize}, process::{Process, ProcessInBg, ProcessInBlock, ProcessInOrphan, ProcessProgBg, ProcessProgBlock, ProcessProgOrphan}};
|
||||||
|
|
||||||
pub struct Scheduler {
|
pub struct Scheduler {
|
||||||
ops: TaskOps,
|
ops: TaskOps,
|
||||||
|
|
@ -163,7 +163,7 @@ impl Scheduler {
|
||||||
let mut ongoing = self.ongoing.lock();
|
let mut ongoing = self.ongoing.lock();
|
||||||
let task = ongoing.add::<FileProgDelete>(format!("Delete {}", target.display()));
|
let task = ongoing.add::<FileProgDelete>(format!("Delete {}", target.display()));
|
||||||
|
|
||||||
task.set_hook(HookInOutDelete { id: task.id, target: target.clone() });
|
task.set_hook(HookInDelete { id: task.id, target: target.clone() });
|
||||||
self.queue(FileInDelete { id: task.id, target, cha: None }, LOW);
|
self.queue(FileInDelete { id: task.id, target, cha: None }, LOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -171,7 +171,7 @@ impl Scheduler {
|
||||||
let mut ongoing = self.ongoing.lock();
|
let mut ongoing = self.ongoing.lock();
|
||||||
let task = ongoing.add::<FileProgTrash>(format!("Trash {}", target.display()));
|
let task = ongoing.add::<FileProgTrash>(format!("Trash {}", target.display()));
|
||||||
|
|
||||||
task.set_hook(HookInOutTrash { id: task.id, target: target.clone() });
|
task.set_hook(HookInTrash { id: task.id, target: target.clone() });
|
||||||
self.queue(FileInTrash { id: task.id, target }, LOW);
|
self.queue(FileInTrash { id: task.id, target }, LOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -179,8 +179,8 @@ impl Scheduler {
|
||||||
let mut ongoing = self.ongoing.lock();
|
let mut ongoing = self.ongoing.lock();
|
||||||
let task = ongoing.add::<FileProgDownload>(format!("Download {}", url.display()));
|
let task = ongoing.add::<FileProgDownload>(format!("Download {}", url.display()));
|
||||||
|
|
||||||
task.set_hook(HookInOutDownload { id: task.id });
|
|
||||||
if url.kind().is_remote() {
|
if url.kind().is_remote() {
|
||||||
|
task.set_hook(HookInDownload { id: task.id });
|
||||||
self.queue(
|
self.queue(
|
||||||
FileInDownload { id: task.id, url, cha: None, retry: 0, done: task.done.clone() },
|
FileInDownload { id: task.id, url, cha: None, retry: 0, done: task.done.clone() },
|
||||||
LOW,
|
LOW,
|
||||||
|
|
@ -202,6 +202,7 @@ impl Scheduler {
|
||||||
.out(task.id, FileOutUpload::Fail("Cannot upload non-remote file".to_owned()));
|
.out(task.id, FileOutUpload::Fail("Cannot upload non-remote file".to_owned()));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
task.set_hook(HookInUpload { id: task.id, target: url.clone() });
|
||||||
self.queue(
|
self.queue(
|
||||||
FileInUpload { id: task.id, url, cha: None, cache: None, done: task.done.clone() },
|
FileInUpload { id: task.id, url, cha: None, cache: None, done: task.done.clone() },
|
||||||
LOW,
|
LOW,
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ pub enum Event {
|
||||||
Key(KeyEvent),
|
Key(KeyEvent),
|
||||||
Mouse(MouseEvent),
|
Mouse(MouseEvent),
|
||||||
Resize,
|
Resize,
|
||||||
|
Focus,
|
||||||
Paste(String),
|
Paste(String),
|
||||||
Quit(EventQuit),
|
Quit(EventQuit),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use std::time::{Duration, SystemTime};
|
use std::time::{Duration, SystemTime};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use hashbrown::HashSet;
|
use hashbrown::HashMap;
|
||||||
use tokio::{pin, sync::mpsc::UnboundedReceiver};
|
use tokio::{pin, sync::mpsc::UnboundedReceiver};
|
||||||
use tokio_stream::{StreamExt, wrappers::UnboundedReceiverStream};
|
use tokio_stream::{StreamExt, wrappers::UnboundedReceiverStream};
|
||||||
use yazi_fs::{File, FilesOp};
|
use yazi_fs::{File, FilesOp};
|
||||||
|
|
@ -14,7 +14,7 @@ use crate::{Reporter, WATCHER};
|
||||||
pub(crate) struct Remote;
|
pub(crate) struct Remote;
|
||||||
|
|
||||||
impl Remote {
|
impl Remote {
|
||||||
pub(crate) fn serve(rx: UnboundedReceiver<UrlBuf>, _reporter: Reporter) -> Self {
|
pub(crate) fn serve(rx: UnboundedReceiver<(UrlBuf, bool)>, _reporter: Reporter) -> Self {
|
||||||
tokio::spawn(Self::changed(rx));
|
tokio::spawn(Self::changed(rx));
|
||||||
|
|
||||||
Self
|
Self
|
||||||
|
|
@ -24,19 +24,22 @@ impl Remote {
|
||||||
|
|
||||||
pub(crate) fn unwatch(&mut self, _url: Url) -> Result<()> { Ok(()) }
|
pub(crate) fn unwatch(&mut self, _url: Url) -> Result<()> { Ok(()) }
|
||||||
|
|
||||||
async fn changed(rx: UnboundedReceiver<UrlBuf>) {
|
async fn changed(rx: UnboundedReceiver<(UrlBuf, bool)>) {
|
||||||
let rx = UnboundedReceiverStream::new(rx).chunks_timeout(1000, Duration::from_millis(250));
|
let rx = UnboundedReceiverStream::new(rx).chunks_timeout(1000, Duration::from_millis(250));
|
||||||
pin!(rx);
|
pin!(rx);
|
||||||
|
|
||||||
while let Some(chunk) = rx.next().await {
|
while let Some(chunk) = rx.next().await {
|
||||||
let urls: HashSet<_> = chunk.into_iter().collect();
|
let mut urls = HashMap::with_capacity(chunk.len());
|
||||||
|
for (u, upload) in chunk {
|
||||||
|
urls.entry(u).and_modify(|b| *b |= upload).or_insert(upload);
|
||||||
|
}
|
||||||
|
|
||||||
let _permit = WATCHER.acquire().await.unwrap();
|
let _permit = WATCHER.acquire().await.unwrap();
|
||||||
|
|
||||||
let mut ops = Vec::with_capacity(urls.len());
|
let mut ops = Vec::with_capacity(urls.len());
|
||||||
let mut ups = Vec::with_capacity(urls.len());
|
let mut ups = Vec::with_capacity(urls.len());
|
||||||
|
|
||||||
for u in urls {
|
for (u, upload) in urls {
|
||||||
let Some((parent, urn)) = u.pair() else { continue };
|
let Some((parent, urn)) = u.pair() else { continue };
|
||||||
let Ok(mut file) = File::new(&u).await else {
|
let Ok(mut file) = File::new(&u).await else {
|
||||||
ops.push(FilesOp::Deleting(parent.into(), [urn.into()].into()));
|
ops.push(FilesOp::Deleting(parent.into(), [urn.into()].into()));
|
||||||
|
|
@ -47,7 +50,7 @@ impl Remote {
|
||||||
file.cha.ctime = Some(SystemTime::now());
|
file.cha.ctime = Some(SystemTime::now());
|
||||||
|
|
||||||
ops.push(FilesOp::Upserting(parent.into(), [(urn.into(), file)].into()));
|
ops.push(FilesOp::Upserting(parent.into(), [(urn.into(), file)].into()));
|
||||||
if is_file {
|
if upload && is_file {
|
||||||
ups.push(u);
|
ups.push(u);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ use crate::{WATCHED, local::LINKED};
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub(crate) struct Reporter {
|
pub(crate) struct Reporter {
|
||||||
pub(super) local_tx: mpsc::UnboundedSender<UrlBuf>,
|
pub(super) local_tx: mpsc::UnboundedSender<UrlBuf>,
|
||||||
pub(super) remote_tx: mpsc::UnboundedSender<UrlBuf>,
|
pub(super) remote_tx: mpsc::UnboundedSender<(UrlBuf, bool)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Reporter {
|
impl Reporter {
|
||||||
|
|
@ -49,9 +49,9 @@ impl Reporter {
|
||||||
let Some(dir) = watched.find_by_cache(parent.loc()) else { continue };
|
let Some(dir) = watched.find_by_cache(parent.loc()) else { continue };
|
||||||
let Some(name) = url.name() else { continue };
|
let Some(name) = url.name() else { continue };
|
||||||
if let Ok(u) = dir.try_join(Cow::from(percent_decode(name.encoded_bytes()))) {
|
if let Ok(u) = dir.try_join(Cow::from(percent_decode(name.encoded_bytes()))) {
|
||||||
self.remote_tx.send(u).ok();
|
self.remote_tx.send((u, true)).ok();
|
||||||
}
|
}
|
||||||
self.remote_tx.send(dir).ok();
|
self.remote_tx.send((dir, false)).ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -61,7 +61,7 @@ impl Reporter {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.remote_tx.send(parent.to_owned()).ok();
|
self.remote_tx.send((parent.to_owned(), false)).ok();
|
||||||
self.remote_tx.send(url.into_owned()).ok();
|
self.remote_tx.send((url.into_owned(), false)).ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue