mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
feat: add "trash" event for trashing files
This commit is contained in:
parent
9f3229a370
commit
0a93a4e9a4
7 changed files with 73 additions and 3 deletions
|
|
@ -2,7 +2,7 @@ use anyhow::Result;
|
||||||
use mlua::{ExternalResult, IntoLua, Lua, Value};
|
use mlua::{ExternalResult, IntoLua, Lua, Value};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
use super::{BodyBulk, BodyCd, BodyCustom, BodyDelete, BodyHey, BodyHi, BodyHover, BodyMove, BodyRename, BodyYank};
|
use super::{BodyBulk, BodyCd, BodyCustom, BodyDelete, BodyHey, BodyHi, BodyHover, BodyMove, BodyRename, BodyTrash, BodyYank};
|
||||||
use crate::Payload;
|
use crate::Payload;
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
|
|
@ -17,6 +17,7 @@ pub enum Body<'a> {
|
||||||
Yank(BodyYank<'a>),
|
Yank(BodyYank<'a>),
|
||||||
Move(BodyMove<'a>),
|
Move(BodyMove<'a>),
|
||||||
Delete(BodyDelete<'a>),
|
Delete(BodyDelete<'a>),
|
||||||
|
Trash(BodyTrash<'a>),
|
||||||
Custom(BodyCustom),
|
Custom(BodyCustom),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -32,6 +33,7 @@ impl<'a> Body<'a> {
|
||||||
"yank" => Body::Yank(serde_json::from_str(body)?),
|
"yank" => Body::Yank(serde_json::from_str(body)?),
|
||||||
"move" => Body::Move(serde_json::from_str(body)?),
|
"move" => Body::Move(serde_json::from_str(body)?),
|
||||||
"delete" => Body::Delete(serde_json::from_str(body)?),
|
"delete" => Body::Delete(serde_json::from_str(body)?),
|
||||||
|
"trash" => Body::Trash(serde_json::from_str(body)?),
|
||||||
_ => BodyCustom::from_str(kind, body)?,
|
_ => BodyCustom::from_str(kind, body)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -60,6 +62,7 @@ impl<'a> Body<'a> {
|
||||||
Self::Yank(_) => "yank",
|
Self::Yank(_) => "yank",
|
||||||
Body::Move(_) => "move",
|
Body::Move(_) => "move",
|
||||||
Body::Delete(_) => "delete",
|
Body::Delete(_) => "delete",
|
||||||
|
Body::Trash(_) => "trash",
|
||||||
Self::Custom(b) => b.kind.as_str(),
|
Self::Custom(b) => b.kind.as_str(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -102,6 +105,7 @@ impl IntoLua<'_> for Body<'static> {
|
||||||
Body::Yank(b) => b.into_lua(lua),
|
Body::Yank(b) => b.into_lua(lua),
|
||||||
Body::Move(b) => b.into_lua(lua),
|
Body::Move(b) => b.into_lua(lua),
|
||||||
Body::Delete(b) => b.into_lua(lua),
|
Body::Delete(b) => b.into_lua(lua),
|
||||||
|
Body::Trash(b) => b.into_lua(lua),
|
||||||
Body::Custom(b) => b.into_lua(lua),
|
Body::Custom(b) => b.into_lua(lua),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ mod hi;
|
||||||
mod hover;
|
mod hover;
|
||||||
mod move_;
|
mod move_;
|
||||||
mod rename;
|
mod rename;
|
||||||
|
mod trash;
|
||||||
mod yank;
|
mod yank;
|
||||||
|
|
||||||
pub use body::*;
|
pub use body::*;
|
||||||
|
|
@ -22,4 +23,5 @@ pub use hi::*;
|
||||||
pub use hover::*;
|
pub use hover::*;
|
||||||
pub use move_::*;
|
pub use move_::*;
|
||||||
pub use rename::*;
|
pub use rename::*;
|
||||||
|
pub use trash::*;
|
||||||
pub use yank::*;
|
pub use yank::*;
|
||||||
|
|
|
||||||
36
yazi-dds/src/body/trash.rs
Normal file
36
yazi-dds/src/body/trash.rs
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
use std::borrow::Cow;
|
||||||
|
|
||||||
|
use mlua::{IntoLua, Lua, Value};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use yazi_shared::fs::Url;
|
||||||
|
|
||||||
|
use super::Body;
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct BodyTrash<'a> {
|
||||||
|
pub urls: Cow<'a, Vec<Url>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> BodyTrash<'a> {
|
||||||
|
#[inline]
|
||||||
|
pub fn borrowed(urls: &'a Vec<Url>) -> Body<'a> { Self { urls: Cow::Borrowed(urls) }.into() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BodyTrash<'static> {
|
||||||
|
#[inline]
|
||||||
|
pub fn owned(urls: Vec<Url>) -> Body<'static> { Self { urls: Cow::Owned(urls) }.into() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<BodyTrash<'a>> for Body<'a> {
|
||||||
|
fn from(value: BodyTrash<'a>) -> Self { Self::Trash(value) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoLua<'_> for BodyTrash<'static> {
|
||||||
|
fn into_lua(self, lua: &Lua) -> mlua::Result<Value<'_>> {
|
||||||
|
let t = lua.create_table_with_capacity(self.urls.len(), 0)?;
|
||||||
|
for (i, url) in self.urls.into_owned().into_iter().enumerate() {
|
||||||
|
t.raw_set(i + 1, lua.create_any_userdata(url)?)?;
|
||||||
|
}
|
||||||
|
t.into_lua(lua)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -86,6 +86,7 @@ impl Display for Payload<'_> {
|
||||||
Body::Yank(b) => serde_json::to_string(b),
|
Body::Yank(b) => serde_json::to_string(b),
|
||||||
Body::Move(b) => serde_json::to_string(b),
|
Body::Move(b) => serde_json::to_string(b),
|
||||||
Body::Delete(b) => serde_json::to_string(b),
|
Body::Delete(b) => serde_json::to_string(b),
|
||||||
|
Body::Trash(b) => serde_json::to_string(b),
|
||||||
Body::Custom(b) => serde_json::to_string(b),
|
Body::Custom(b) => serde_json::to_string(b),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use parking_lot::RwLock;
|
||||||
use yazi_boot::BOOT;
|
use yazi_boot::BOOT;
|
||||||
use yazi_shared::{fs::Url, RoCell};
|
use yazi_shared::{fs::Url, RoCell};
|
||||||
|
|
||||||
use crate::{body::{Body, BodyCd, BodyDelete, BodyHi, BodyHover, BodyMove, BodyMoveItem, BodyRename, BodyYank}, Client, ID, PEERS};
|
use crate::{body::{Body, BodyCd, BodyDelete, BodyHi, BodyHover, BodyMove, BodyMoveItem, BodyRename, BodyTrash, BodyYank}, Client, ID, PEERS};
|
||||||
|
|
||||||
pub static LOCAL: RoCell<RwLock<HashMap<String, HashMap<String, Function<'static>>>>> =
|
pub static LOCAL: RoCell<RwLock<HashMap<String, HashMap<String, Function<'static>>>>> =
|
||||||
RoCell::new();
|
RoCell::new();
|
||||||
|
|
@ -166,4 +166,16 @@ impl Pubsub {
|
||||||
Self::pub_(BodyDelete::owned(urls));
|
Self::pub_(BodyDelete::owned(urls));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn pub_from_trash(urls: Vec<Url>) {
|
||||||
|
if PEERS.read().values().any(|p| p.able("trash")) {
|
||||||
|
Client::push(BodyTrash::borrowed(&urls));
|
||||||
|
}
|
||||||
|
if BOOT.local_events.contains("trash") {
|
||||||
|
BodyTrash::borrowed(&urls).with_receiver(*ID).flush();
|
||||||
|
}
|
||||||
|
if LOCAL.read().contains_key("trash") {
|
||||||
|
Self::pub_(BodyTrash::owned(urls));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ use crate::{body::BodyMoveItem, Pubsub};
|
||||||
static CT: RoCell<CancellationToken> = RoCell::new();
|
static CT: RoCell<CancellationToken> = RoCell::new();
|
||||||
static MOVE_TX: Mutex<Option<mpsc::UnboundedSender<BodyMoveItem>>> = Mutex::new(None);
|
static MOVE_TX: Mutex<Option<mpsc::UnboundedSender<BodyMoveItem>>> = Mutex::new(None);
|
||||||
static DELETE_TX: Mutex<Option<mpsc::UnboundedSender<Url>>> = Mutex::new(None);
|
static DELETE_TX: Mutex<Option<mpsc::UnboundedSender<Url>>> = Mutex::new(None);
|
||||||
|
static TRASH_TX: Mutex<Option<mpsc::UnboundedSender<Url>>> = Mutex::new(None);
|
||||||
|
|
||||||
pub struct Pump;
|
pub struct Pump;
|
||||||
|
|
||||||
|
|
@ -29,27 +30,40 @@ impl Pump {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn push_trash(target: Url) {
|
||||||
|
if let Some(tx) = &*TRASH_TX.lock() {
|
||||||
|
tx.send(target).ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn serve() {
|
pub(super) fn serve() {
|
||||||
let (move_tx, move_rx) = mpsc::unbounded_channel();
|
let (move_tx, move_rx) = mpsc::unbounded_channel();
|
||||||
let (delete_tx, delete_rx) = mpsc::unbounded_channel();
|
let (delete_tx, delete_rx) = mpsc::unbounded_channel();
|
||||||
|
let (trash_tx, trash_rx) = mpsc::unbounded_channel();
|
||||||
|
|
||||||
CT.with(Default::default);
|
CT.with(Default::default);
|
||||||
MOVE_TX.lock().replace(move_tx);
|
MOVE_TX.lock().replace(move_tx);
|
||||||
DELETE_TX.lock().replace(delete_tx);
|
DELETE_TX.lock().replace(delete_tx);
|
||||||
|
TRASH_TX.lock().replace(trash_tx);
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let move_rx =
|
let move_rx =
|
||||||
UnboundedReceiverStream::new(move_rx).chunks_timeout(1000, Duration::from_millis(500));
|
UnboundedReceiverStream::new(move_rx).chunks_timeout(1000, Duration::from_millis(500));
|
||||||
let delete_rx =
|
let delete_rx =
|
||||||
UnboundedReceiverStream::new(delete_rx).chunks_timeout(1000, Duration::from_millis(500));
|
UnboundedReceiverStream::new(delete_rx).chunks_timeout(1000, Duration::from_millis(500));
|
||||||
|
let trash_rx =
|
||||||
|
UnboundedReceiverStream::new(trash_rx).chunks_timeout(1000, Duration::from_millis(500));
|
||||||
|
|
||||||
pin!(move_rx);
|
pin!(move_rx);
|
||||||
pin!(delete_rx);
|
pin!(delete_rx);
|
||||||
|
pin!(trash_rx);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
select! {
|
select! {
|
||||||
Some(items) = move_rx.next() => Pubsub::pub_from_move(items),
|
Some(items) = move_rx.next() => Pubsub::pub_from_move(items),
|
||||||
Some(urls) = delete_rx.next() => Pubsub::pub_from_delete(urls),
|
Some(urls) = delete_rx.next() => Pubsub::pub_from_delete(urls),
|
||||||
|
Some(urls) = trash_rx.next() => Pubsub::pub_from_trash(urls),
|
||||||
else => {
|
else => {
|
||||||
CT.cancel();
|
CT.cancel();
|
||||||
break;
|
break;
|
||||||
|
|
@ -62,6 +76,7 @@ impl Pump {
|
||||||
pub(super) async fn shutdown() {
|
pub(super) async fn shutdown() {
|
||||||
drop(MOVE_TX.lock().take());
|
drop(MOVE_TX.lock().take());
|
||||||
drop(DELETE_TX.lock().take());
|
drop(DELETE_TX.lock().take());
|
||||||
|
drop(TRASH_TX.lock().take());
|
||||||
CT.cancelled().await;
|
CT.cancelled().await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -175,7 +175,7 @@ impl Scheduler {
|
||||||
_ = self.micro.try_send(
|
_ = self.micro.try_send(
|
||||||
async move {
|
async move {
|
||||||
file.trash(FileOpTrash { id, target: target.clone(), length: 0 }).await.ok();
|
file.trash(FileOpTrash { id, target: target.clone(), length: 0 }).await.ok();
|
||||||
Pump::push_delete(target);
|
Pump::push_trash(target);
|
||||||
}
|
}
|
||||||
.boxed(),
|
.boxed(),
|
||||||
LOW,
|
LOW,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue