diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e036620..4e66c785 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,9 +18,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/): - Allow using `ps.sub()` in `init.lua` directly without a plugin ([#3638]) - New `sort_fallback` option to control fallback sorting behavior ([#3077]) - New `fs.access()` API to access the filesystem ([#3668]) -- New `relay-notify-push` DDS event to customize notification handlers ([#3642]) +- New `relay-notify-push` DDS event to customize the notification handler ([#3642]) - New `ind-app-title` DDS event to customize the app title ([#3684]) - New `fs.unique()` creates a unique file or directory ([#3677]) +- New `download` DDS event fires when remote files are downloaded ([#3687]) - New `cx.which` API to access the which component state ([#3617]) - New `ind-which-activate` DDS event to change the which component behavior ([#3608]) @@ -1660,3 +1661,4 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/): [#3677]: https://github.com/sxyazi/yazi/pull/3677 [#3678]: https://github.com/sxyazi/yazi/pull/3678 [#3684]: https://github.com/sxyazi/yazi/pull/3684 +[#3687]: https://github.com/sxyazi/yazi/pull/3687 diff --git a/Cargo.lock b/Cargo.lock index 9c86d96e..095f7493 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -186,7 +186,7 @@ checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -500,7 +500,7 @@ checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -658,7 +658,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -990,7 +990,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -1034,7 +1034,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -1048,7 +1048,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -1061,7 +1061,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -1072,7 +1072,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core 0.20.11", "quote", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -1083,7 +1083,7 @@ checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ "darling_core 0.21.3", "quote", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -1094,7 +1094,7 @@ checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" dependencies = [ "darling_core 0.23.0", "quote", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -1132,7 +1132,7 @@ checksum = "780eb241654bf097afb00fc5f054a09b687dad862e485fdcf8399bb056565370" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -1191,7 +1191,7 @@ dependencies = [ "darling 0.20.11", "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -1201,7 +1201,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -1223,7 +1223,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -1366,7 +1366,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -1392,7 +1392,7 @@ checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -1495,7 +1495,7 @@ checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -1607,9 +1607,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" dependencies = [ "futures-channel", "futures-core", @@ -1622,9 +1622,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" dependencies = [ "futures-core", "futures-sink", @@ -1632,15 +1632,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-executor" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" dependencies = [ "futures-core", "futures-task", @@ -1649,38 +1649,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] name = "futures-macro" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] name = "futures-sink" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-channel", "futures-core", @@ -1690,7 +1690,6 @@ dependencies = [ "futures-task", "memchr", "pin-project-lite", - "pin-utils", "slab", ] @@ -1864,7 +1863,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -2087,7 +2086,7 @@ dependencies = [ "indoc", "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -2129,7 +2128,7 @@ checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -2539,7 +2538,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -2683,7 +2682,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -2939,7 +2938,7 @@ dependencies = [ "by_address", "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -3058,7 +3057,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -3111,7 +3110,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -3129,12 +3128,6 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - [[package]] name = "pkcs1" version = "0.8.0-rc.4" @@ -3265,7 +3258,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -3296,7 +3289,7 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -3324,7 +3317,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b" dependencies = [ "quote", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -3671,7 +3664,7 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -4022,7 +4015,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -4075,7 +4068,7 @@ dependencies = [ "darling 0.21.3", "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -4360,7 +4353,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -4382,9 +4375,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.115" +version = "2.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e614ed320ac28113fa64972c4262d5dbc89deacdfd00c34a3e4cea073243c12" +checksum = "3df424c70518695237746f84cede799c9c58fcb37450d7b23716568cc8bc69cb" dependencies = [ "proc-macro2", "quote", @@ -4518,7 +4511,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -4529,7 +4522,7 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -4626,7 +4619,7 @@ checksum = "2d2e76690929402faae40aebdda620a2c0e25dd6d3b9afe48867dfd95991f4bd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -4654,7 +4647,7 @@ checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -4751,7 +4744,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -4846,9 +4839,9 @@ checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" [[package]] name = "unicode-ident" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "537dd038a89878be9b64dd4bd1b260315c1bb94f4d784956b81e27a088d9a09e" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-segmentation" @@ -5081,7 +5074,7 @@ dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.116", "wasm-bindgen-shared", ] @@ -5345,7 +5338,7 @@ checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -5356,7 +5349,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -5367,7 +5360,7 @@ checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -5378,7 +5371,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -5640,7 +5633,7 @@ dependencies = [ "heck", "indexmap 2.13.0", "prettyplease", - "syn 2.0.115", + "syn 2.0.116", "wasm-metadata", "wit-bindgen-core", "wit-component", @@ -5656,7 +5649,7 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.116", "wit-bindgen-core", "wit-bindgen-rust", ] @@ -5857,7 +5850,7 @@ name = "yazi-codegen" version = "26.2.2" dependencies = [ "quote", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -6316,7 +6309,7 @@ checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] @@ -6336,7 +6329,7 @@ checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.115", + "syn 2.0.116", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 75115c1c..03f07117 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,7 +37,7 @@ dirs = "6.0.0" dyn-clone = "1.0.20" either = { version = "1.15.0" } foldhash = "0.2.0" -futures = "0.3.31" +futures = "0.3.32" globset = "0.4.18" hashbrown = { version = "0.16.1", features = [ "serde" ] } indexmap = { version = "2.13.0", features = [ "serde" ] } diff --git a/yazi-codegen/Cargo.toml b/yazi-codegen/Cargo.toml index 06ff760d..a3f5a323 100644 --- a/yazi-codegen/Cargo.toml +++ b/yazi-codegen/Cargo.toml @@ -16,5 +16,5 @@ proc-macro = true [dependencies] # External dependencies -syn = { version = "2.0.115", features = [ "full" ] } +syn = { version = "2.0.116", features = [ "full" ] } quote = "1.0.44" diff --git a/yazi-config/preset/keymap-default.toml b/yazi-config/preset/keymap-default.toml index bde93914..447cb98e 100644 --- a/yazi-config/preset/keymap-default.toml +++ b/yazi-config/preset/keymap-default.toml @@ -94,10 +94,10 @@ keymap = [ { on = [ "m", "n" ], run = "linemode none", desc = "Linemode: none" }, # Copy - { on = [ "c", "c" ], run = "copy path", desc = "Copy the file path" }, - { on = [ "c", "d" ], run = "copy dirname", desc = "Copy the directory path" }, - { on = [ "c", "f" ], run = "copy filename", desc = "Copy the filename" }, - { on = [ "c", "n" ], run = "copy name_without_ext", desc = "Copy the filename without extension" }, + { on = [ "c", "c" ], run = "copy path", desc = "Copy file URL" }, + { on = [ "c", "d" ], run = "copy dirname", desc = "Copy directory URL" }, + { on = [ "c", "f" ], run = "copy filename", desc = "Copy filename" }, + { on = [ "c", "n" ], run = "copy name_without_ext", desc = "Copy filename without extension" }, # Filter { on = "f", run = "filter --smart", desc = "Filter files" }, diff --git a/yazi-dds/src/ember/download.rs b/yazi-dds/src/ember/download.rs new file mode 100644 index 00000000..776e4e18 --- /dev/null +++ b/yazi-dds/src/ember/download.rs @@ -0,0 +1,33 @@ +use std::borrow::Cow; + +use mlua::{IntoLua, Lua, Value}; +use serde::{Deserialize, Serialize}; +use yazi_shared::url::UrlBuf; + +use super::Ember; + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct EmberDownload<'a> { + pub urls: Cow<'a, Vec>, +} + +impl<'a> EmberDownload<'a> { + pub fn borrowed(urls: &'a Vec) -> Ember<'a> { Self { urls: Cow::Borrowed(urls) }.into() } +} + +impl EmberDownload<'static> { + pub fn owned(urls: Vec) -> Ember<'static> { Self { urls: Cow::Owned(urls) }.into() } +} + +impl<'a> From> for Ember<'a> { + fn from(value: EmberDownload<'a>) -> Self { Self::Download(value) } +} + +impl IntoLua for EmberDownload<'_> { + fn into_lua(self, lua: &Lua) -> mlua::Result { + let urls = + lua.create_sequence_from(self.urls.into_owned().into_iter().map(yazi_binding::Url::new))?; + + lua.create_table_from([("urls", urls)])?.into_lua(lua) + } +} diff --git a/yazi-dds/src/ember/ember.rs b/yazi-dds/src/ember/ember.rs index 230e73dd..e37a9066 100644 --- a/yazi-dds/src/ember/ember.rs +++ b/yazi-dds/src/ember/ember.rs @@ -2,7 +2,7 @@ use anyhow::{Result, bail}; use mlua::{ExternalResult, IntoLua, Lua, Value}; use yazi_shared::Id; -use super::{EmberBulk, EmberBye, EmberCd, EmberCustom, EmberDelete, EmberDuplicate, EmberHey, EmberHi, EmberHover, EmberLoad, EmberMount, EmberMove, EmberRename, EmberTab, EmberTrash, EmberYank}; +use super::{EmberBulk, EmberBye, EmberCd, EmberCustom, EmberDelete, EmberDownload, EmberDuplicate, EmberHey, EmberHi, EmberHover, EmberLoad, EmberMount, EmberMove, EmberRename, EmberTab, EmberTrash, EmberYank}; use crate::Payload; #[derive(Clone, Debug)] @@ -21,6 +21,7 @@ pub enum Ember<'a> { Move(EmberMove<'a>), Trash(EmberTrash<'a>), Delete(EmberDelete<'a>), + Download(EmberDownload<'a>), Mount(EmberMount), Custom(EmberCustom), } @@ -42,6 +43,7 @@ impl Ember<'static> { "move" => Self::Move(serde_json::from_str(body)?), "trash" => Self::Trash(serde_json::from_str(body)?), "delete" => Self::Delete(serde_json::from_str(body)?), + "download" => Self::Download(serde_json::from_str(body)?), "mount" => Self::Mount(serde_json::from_str(body)?), _ => EmberCustom::from_str(kind, body)?, }) @@ -69,6 +71,7 @@ impl Ember<'static> { | "move" | "trash" | "delete" + | "download" | "mount" ) || kind.starts_with("key-") || kind.starts_with("ind-") @@ -107,6 +110,7 @@ impl<'a> Ember<'a> { Self::Move(_) => "move", Self::Trash(_) => "trash", Self::Delete(_) => "delete", + Self::Download(_) => "download", Self::Mount(_) => "mount", Self::Custom(b) => b.kind.as_str(), } @@ -136,6 +140,7 @@ impl<'a> IntoLua for Ember<'a> { Self::Move(b) => b.into_lua(lua), Self::Trash(b) => b.into_lua(lua), Self::Delete(b) => b.into_lua(lua), + Self::Download(b) => b.into_lua(lua), Self::Mount(b) => b.into_lua(lua), Self::Custom(b) => b.into_lua(lua), } diff --git a/yazi-dds/src/ember/mod.rs b/yazi-dds/src/ember/mod.rs index d6be0cc9..28711e9d 100644 --- a/yazi-dds/src/ember/mod.rs +++ b/yazi-dds/src/ember/mod.rs @@ -1,3 +1,3 @@ yazi_macro::mod_flat!( - bulk bye cd custom delete duplicate ember hey hi hover load mount r#move rename tab trash yank + bulk bye cd custom delete download duplicate ember hey hi hover load mount r#move rename tab trash yank ); diff --git a/yazi-dds/src/payload.rs b/yazi-dds/src/payload.rs index 4dc5f43f..ec5be04a 100644 --- a/yazi-dds/src/payload.rs +++ b/yazi-dds/src/payload.rs @@ -113,6 +113,7 @@ impl Display for Payload<'_> { Ember::Move(b) => serde_json::to_string(b), Ember::Trash(b) => serde_json::to_string(b), Ember::Delete(b) => serde_json::to_string(b), + Ember::Download(b) => serde_json::to_string(b), Ember::Mount(b) => serde_json::to_string(b), Ember::Custom(b) => serde_json::to_string(b), }; diff --git a/yazi-dds/src/pubsub.rs b/yazi-dds/src/pubsub.rs index e51f78d3..f25297f9 100644 --- a/yazi-dds/src/pubsub.rs +++ b/yazi-dds/src/pubsub.rs @@ -165,5 +165,7 @@ impl Pubsub { pub_after!(delete(urls: Vec), (&urls), (urls)); + pub_after!(download(urls: Vec), (&urls), (urls)); + pub_after!(mount(), ()); } diff --git a/yazi-dds/src/pump.rs b/yazi-dds/src/pump.rs index 63aa2050..0948a826 100644 --- a/yazi-dds/src/pump.rs +++ b/yazi-dds/src/pump.rs @@ -11,6 +11,7 @@ static DUPLICATE_TX: RoCell> = RoCell:: static MOVE_TX: RoCell> = RoCell::new(); static TRASH_TX: RoCell> = RoCell::new(); static DELETE_TX: RoCell> = RoCell::new(); +static DOWNLOAD_TX: RoCell> = RoCell::new(); static SHUTDOWN_TX: RoCell> = RoCell::new(); pub struct Pump; @@ -44,17 +45,26 @@ impl Pump { DELETE_TX.send(target.into()).ok(); } + pub fn push_download(target: U) + where + U: Into, + { + DOWNLOAD_TX.send(target.into()).ok(); + } + pub(super) fn serve() { let (move_tx, move_rx) = mpsc::unbounded_channel(); let (duplicate_tx, duplicate_rx) = mpsc::unbounded_channel(); let (trash_tx, trash_rx) = mpsc::unbounded_channel(); let (delete_tx, delete_rx) = mpsc::unbounded_channel(); + let (download_tx, download_rx) = mpsc::unbounded_channel(); let (shutdown_tx, mut shutdown_rx) = mpsc::unbounded_channel(); DUPLICATE_TX.init(duplicate_tx); MOVE_TX.init(move_tx); TRASH_TX.init(trash_tx); DELETE_TX.init(delete_tx); + DOWNLOAD_TX.init(download_tx); SHUTDOWN_TX.init(shutdown_tx); tokio::spawn(async move { @@ -66,11 +76,14 @@ impl Pump { UnboundedReceiverStream::new(trash_rx).chunks_timeout(1000, Duration::from_millis(500)); let delete_rx = UnboundedReceiverStream::new(delete_rx).chunks_timeout(1000, Duration::from_millis(500)); + let download_rx = + UnboundedReceiverStream::new(download_rx).chunks_timeout(1000, Duration::from_millis(500)); pin!(duplicate_rx); pin!(move_rx); pin!(trash_rx); pin!(delete_rx); + pin!(download_rx); loop { select! { @@ -78,6 +91,7 @@ impl Pump { Some(items) = move_rx.next() => err!(Pubsub::pub_after_move(items)), Some(urls) = trash_rx.next() => err!(Pubsub::pub_after_trash(urls)), Some(urls) = delete_rx.next() => err!(Pubsub::pub_after_delete(urls)), + Some(urls) = download_rx.next() => err!(Pubsub::pub_after_download(urls)), _ = shutdown_rx.recv() => { shutdown_rx.close(); break; diff --git a/yazi-fs/src/sorter.rs b/yazi-fs/src/sorter.rs index 9a889c7d..cadeea30 100644 --- a/yazi-fs/src/sorter.rs +++ b/yazi-fs/src/sorter.rs @@ -112,8 +112,11 @@ impl FilesSorter { } match self.fallback { - SortFallback::Alphabetical => self.sort_alphabetically(a, b), - SortFallback::Natural => self.sort_naturally(a, b), + SortFallback::Alphabetical => self.cmp(a.urn().encoded_bytes(), b.urn().encoded_bytes()), + SortFallback::Natural => { + let ord = natsort(a.urn().encoded_bytes(), b.urn().encoded_bytes(), false); + if self.reverse { ord.reverse() } else { ord } + } } } diff --git a/yazi-scheduler/src/file/file.rs b/yazi-scheduler/src/file/file.rs index f9e29764..6a529ec7 100644 --- a/yazi-scheduler/src/file/file.rs +++ b/yazi-scheduler/src/file/file.rs @@ -335,17 +335,17 @@ impl File { ) -> Result<(), FileOutDownloadDo> { let cha = task.cha.unwrap(); - let cache = ctx!(task, task.url.cache(), "Cannot determine cache path")?; + let cache = ctx!(task, task.target.cache(), "Cannot determine cache path")?; let cache_tmp = ctx!(task, Transaction::tmp(&cache).await, "Cannot determine download cache")?; - let mut it = ctx!(task, provider::copy_with_progress(&task.url, &cache_tmp, cha).await)?; + let mut it = ctx!(task, provider::copy_with_progress(&task.target, &cache_tmp, cha).await)?; loop { match progress_or_break!(it, task.done) { Ok(0) => { Local::regular(&cache).remove_dir_all().await.ok(); ctx!(task, provider::rename(cache_tmp, cache).await, "Cannot persist downloaded file")?; - let lock = ctx!(task, task.url.cache_lock(), "Cannot determine cache lock")?; + let lock = ctx!(task, task.target.cache_lock(), "Cannot determine cache lock")?; let hash = format!("{:x}", cha.hash_u128()); ctx!(task, Local::regular(&lock).write(hash).await, "Cannot lock cache")?; @@ -403,7 +403,7 @@ impl File { pub(crate) async fn upload_do(&self, task: FileInUpload) -> Result<(), FileOutUploadDo> { let cha = task.cha.unwrap(); let cache = ctx!(task, task.cache.as_ref(), "Cannot determine cache path")?; - let lock = ctx!(task, task.url.cache_lock(), "Cannot determine cache lock")?; + let lock = ctx!(task, task.target.cache_lock(), "Cannot determine cache lock")?; let hash = ctx!(task, Local::regular(&lock).read_to_string().await, "Cannot read cache lock")?; let hash = ctx!(task, u128::from_str_radix(&hash, 16), "Cannot parse hash from lock")?; @@ -412,7 +412,7 @@ impl File { } let tmp = - ctx!(task, Transaction::tmp(&task.url).await, "Cannot determine temporary upload path")?; + ctx!(task, Transaction::tmp(&task.target).await, "Cannot determine temporary upload path")?; let mut it = ctx!( task, provider::copy_with_progress(cache, &tmp, Attrs { @@ -428,15 +428,15 @@ impl File { match progress_or_break!(it, task.done) { Ok(0) => { let cha = - ctx!(task, Self::cha(&task.url, true, None).await, "Cannot stat original file")?; + ctx!(task, Self::cha(&task.target, true, None).await, "Cannot stat original file")?; if hash != cha.hash_u128() { Err(anyhow!("Failed to work on: {task:?}: remote file has changed during upload"))?; } - ctx!(task, provider::rename(&tmp, &task.url).await, "Cannot persist uploaded file")?; + ctx!(task, provider::rename(&tmp, &task.target).await, "Cannot persist uploaded file")?; let cha = - ctx!(task, Self::cha(&task.url, true, None).await, "Cannot stat uploaded file")?; + ctx!(task, Self::cha(&task.target, true, None).await, "Cannot stat uploaded file")?; let hash = format!("{:x}", cha.hash_u128()); ctx!(task, Local::regular(&lock).write(hash).await, "Cannot lock cache")?; diff --git a/yazi-scheduler/src/file/in.rs b/yazi-scheduler/src/file/in.rs index 77a295d1..898616da 100644 --- a/yazi-scheduler/src/file/in.rs +++ b/yazi-scheduler/src/file/in.rs @@ -187,19 +187,19 @@ pub(crate) struct FileInTrash { // --- Download #[derive(Clone, Debug)] pub(crate) struct FileInDownload { - pub(crate) id: Id, - pub(crate) url: UrlBuf, - pub(crate) cha: Option, - pub(crate) retry: u8, - pub(crate) done: CompletionToken, + pub(crate) id: Id, + pub(crate) target: UrlBuf, + pub(crate) cha: Option, + pub(crate) retry: u8, + pub(crate) done: CompletionToken, } // --- Upload #[derive(Clone, Debug)] pub(crate) struct FileInUpload { - pub(crate) id: Id, - pub(crate) url: UrlBuf, - pub(crate) cha: Option, - pub(crate) cache: Option, - pub(crate) done: CompletionToken, + pub(crate) id: Id, + pub(crate) target: UrlBuf, + pub(crate) cha: Option, + pub(crate) cache: Option, + pub(crate) done: CompletionToken, } diff --git a/yazi-scheduler/src/file/traverse.rs b/yazi-scheduler/src/file/traverse.rs index 345b5acc..37f5beee 100644 --- a/yazi-scheduler/src/file/traverse.rs +++ b/yazi-scheduler/src/file/traverse.rs @@ -112,15 +112,15 @@ impl Traverse for FileInDownload { fn follow(&self) -> bool { true } - fn from(&self) -> Url<'_> { self.url.as_url() } + fn from(&self) -> Url<'_> { self.target.as_url() } fn spawn(&self, from: UrlBuf, _to: Option, cha: Cha) -> Self { Self { - id: self.id, - url: from, - cha: Some(cha), - retry: self.retry, - done: self.done.clone(), + id: self.id, + target: from, + cha: Some(cha), + retry: self.retry, + done: self.done.clone(), } } @@ -132,25 +132,25 @@ impl Traverse for FileInUpload { fn follow(&self) -> bool { true } - fn from(&self) -> Url<'_> { self.url.as_url() } + fn from(&self) -> Url<'_> { self.target.as_url() } async fn init(&mut self) -> anyhow::Result { if self.cha.is_none() { self.cha = Some(super::File::cha(self.from(), self.follow(), None).await?) } if self.cache.is_none() { - self.cache = self.url.cache(); + self.cache = self.target.cache(); } Ok(self.cha.unwrap()) } fn spawn(&self, from: UrlBuf, _to: Option, cha: Cha) -> Self { Self { - id: self.id, - cha: Some(cha), - cache: from.cache(), - url: from, - done: self.done.clone(), + id: self.id, + cha: Some(cha), + cache: from.cache(), + target: from, + done: self.done.clone(), } } diff --git a/yazi-scheduler/src/hook/hook.rs b/yazi-scheduler/src/hook/hook.rs index 4f48ba1b..cfa5a600 100644 --- a/yazi-scheduler/src/hook/hook.rs +++ b/yazi-scheduler/src/hook/hook.rs @@ -68,6 +68,11 @@ impl Hook { } pub(crate) async fn download(&self, task: HookInDownload) { + let intact = self.ongoing.lock().intact(task.id); + if intact { + TasksProxy::update_succeed([&task.target]); + Pump::push_download(task.target); + } self.ops.out(task.id, FileOutDownload::Clean); } diff --git a/yazi-scheduler/src/hook/in.rs b/yazi-scheduler/src/hook/in.rs index 2e4b600f..5b630994 100644 --- a/yazi-scheduler/src/hook/in.rs +++ b/yazi-scheduler/src/hook/in.rs @@ -95,7 +95,8 @@ pub(crate) struct HookInTrash { // --- Download #[derive(Debug)] pub(crate) struct HookInDownload { - pub(crate) id: Id, + pub(crate) id: Id, + pub(crate) target: UrlBuf, } // --- Upload diff --git a/yazi-scheduler/src/scheduler.rs b/yazi-scheduler/src/scheduler.rs index 06f8f979..83a1aa38 100644 --- a/yazi-scheduler/src/scheduler.rs +++ b/yazi-scheduler/src/scheduler.rs @@ -147,14 +147,14 @@ impl Scheduler { self.file.submit(FileInTrash { id: task.id, target }, LOW); } - pub fn file_download(&self, url: UrlBuf) -> CompletionToken { + pub fn file_download(&self, target: UrlBuf) -> CompletionToken { let mut ongoing = self.ongoing.lock(); - let task = ongoing.add::(format!("Download {}", url.display())); + let task = ongoing.add::(format!("Download {}", target.display())); - if url.kind().is_remote() { - task.set_hook(HookInDownload { id: task.id }); + if target.kind().is_remote() { + task.set_hook(HookInDownload { id: task.id, target: target.clone() }); self.file.submit( - FileInDownload { id: task.id, url, cha: None, retry: 0, done: task.done.clone() }, + FileInDownload { id: task.id, target, cha: None, retry: 0, done: task.done.clone() }, LOW, ); } else { @@ -164,19 +164,19 @@ impl Scheduler { task.done.clone() } - pub fn file_upload(&self, url: UrlBuf) { + pub fn file_upload(&self, target: UrlBuf) { let mut ongoing = self.ongoing.lock(); - let task = ongoing.add::(format!("Upload {}", url.display())); + let task = ongoing.add::(format!("Upload {}", target.display())); - if !url.kind().is_remote() { + if !target.kind().is_remote() { return self .ops .out(task.id, FileOutUpload::Fail("Cannot upload non-remote file".to_owned())); }; - task.set_hook(HookInUpload { id: task.id, target: url.clone() }); + task.set_hook(HookInUpload { id: task.id, target: target.clone() }); self.file.submit( - FileInUpload { id: task.id, url, cha: None, cache: None, done: task.done.clone() }, + FileInUpload { id: task.id, target, cha: None, cache: None, done: task.done.clone() }, LOW, ); }