From 76196aab70e04065d43bee9ee41eeb1b547995df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E5=92=B2=E9=9B=85=20misaki=20masa?= Date: Sun, 30 Nov 2025 12:08:59 +0800 Subject: [PATCH] refactor!: return `Path` instead of `Url` from `File.link_to` (#3385) --- CHANGELOG.md | 3 ++- Cargo.lock | 4 ++-- yazi-actor/src/mgr/enter.rs | 2 +- yazi-actor/src/mgr/escape.rs | 2 +- yazi-actor/src/mgr/follow.rs | 4 ++-- yazi-actor/src/mgr/refresh.rs | 7 +++++-- yazi-actor/src/mgr/search.rs | 2 +- yazi-actor/src/mgr/stash.rs | 4 ++-- yazi-actor/src/mgr/tab_create.rs | 2 +- yazi-binding/src/macros.rs | 2 +- yazi-core/src/tab/preview.rs | 2 +- yazi-fs/src/file.rs | 19 +------------------ yazi-parser/src/mgr/cd.rs | 1 + yazi-plugin/preset/components/tasks.lua | 8 ++++++-- yazi-shared/src/url/buf.rs | 24 +----------------------- yazi-shared/src/url/cow.rs | 5 ----- yazi-shared/src/url/like.rs | 8 ++++++++ yazi-shared/src/url/url.rs | 14 +++++++++++++- yazi-vfs/src/files.rs | 2 +- 19 files changed, 50 insertions(+), 65 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 07ed6fd5..41a7587b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,7 +45,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/): - Rename `name` to `url` for open, fetchers, spotters, preloaders, previewers, filetype, and `globs` icon rules to support virtual file system ([#3034]) - Rename `mime` fetcher to `mime.local`, and introduce `mime.dir` fetcher to support folder MIME types ([#3222]) - Remove `$0` parameter in opener rules to make the `open` command work under empty directories ([#3226]) -- Return `Path` instead of `Url` from `Url:strip_prefix()` to enforce type safety ([#3361]) +- Return `Path` instead of `Url` from `Url:strip_prefix()` and `File.link_to` to enforce type safety ([#3361], [#3385]) - Use `body` instead of the term `content` in confirmations ([#2921]) - Use `u16` instead of `u32` as the type of `max_width` and `max_height` options to avoid memory exhaustion ([#3313]) - Implement `__pairs` metamethod instead of `__index` for the callback argument of the `@yank` DDS event ([#2997]) @@ -1543,3 +1543,4 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/): [#3360]: https://github.com/sxyazi/yazi/pull/3360 [#3364]: https://github.com/sxyazi/yazi/pull/3364 [#3369]: https://github.com/sxyazi/yazi/pull/3369 +[#3385]: https://github.com/sxyazi/yazi/pull/3385 diff --git a/Cargo.lock b/Cargo.lock index d3a753f9..3267b6f7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1764,9 +1764,9 @@ dependencies = [ [[package]] name = "instability" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435d80800b936787d62688c927b6490e887c7ef5ff9ce922c6c6050fca75eb9a" +checksum = "6778b0196eefee7df739db78758e5cf9b37412268bfa5650bfeed028aed20d9c" dependencies = [ "darling", "indoc", diff --git a/yazi-actor/src/mgr/enter.rs b/yazi-actor/src/mgr/enter.rs index 4ec6ef85..abae6034 100644 --- a/yazi-actor/src/mgr/enter.rs +++ b/yazi-actor/src/mgr/enter.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_macro::{act, succ}; use yazi_parser::{VoidOpt, mgr::CdSource}; -use yazi_shared::data::Data; +use yazi_shared::{data::Data, url::UrlLike}; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/escape.rs b/yazi-actor/src/mgr/escape.rs index aee89094..ed4bbde0 100644 --- a/yazi-actor/src/mgr/escape.rs +++ b/yazi-actor/src/mgr/escape.rs @@ -2,7 +2,7 @@ use anyhow::{Result, bail}; use yazi_macro::{act, render, render_and, succ}; use yazi_parser::{VoidOpt, mgr::EscapeOpt}; use yazi_proxy::AppProxy; -use yazi_shared::data::Data; +use yazi_shared::{data::Data, url::UrlLike}; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/follow.rs b/yazi-actor/src/mgr/follow.rs index c79a3bf9..b0a699dc 100644 --- a/yazi-actor/src/mgr/follow.rs +++ b/yazi-actor/src/mgr/follow.rs @@ -1,7 +1,7 @@ use anyhow::Result; use yazi_fs::path::clean_url; use yazi_macro::{act, succ}; -use yazi_parser::VoidOpt; +use yazi_parser::{VoidOpt, mgr::CdSource}; use yazi_shared::{data::Data, url::UrlLike}; use crate::{Actor, Ctx}; @@ -18,6 +18,6 @@ impl Actor for Follow { let Some(link_to) = &file.link_to else { succ!() }; let Some(parent) = file.url.parent() else { succ!() }; let Ok(joined) = parent.try_join(link_to) else { succ!() }; - act!(mgr:reveal, cx, clean_url(joined)) + act!(mgr:reveal, cx, (clean_url(joined), CdSource::Follow)) } } diff --git a/yazi-actor/src/mgr/refresh.rs b/yazi-actor/src/mgr/refresh.rs index a81599ae..7ca8ff14 100644 --- a/yazi-actor/src/mgr/refresh.rs +++ b/yazi-actor/src/mgr/refresh.rs @@ -57,8 +57,11 @@ impl Refresh { } } - let futs: Vec<_> = - folders.iter().filter(|&f| f.url.is_internal()).map(|&f| go(f.url.clone(), f.cha)).collect(); + let futs: Vec<_> = folders + .iter() + .filter(|&f| f.url.is_absolute() && f.url.is_internal()) + .map(|&f| go(f.url.clone(), f.cha)) + .collect(); if !futs.is_empty() { tokio::spawn(futures::future::join_all(futs)); diff --git a/yazi-actor/src/mgr/search.rs b/yazi-actor/src/mgr/search.rs index b559f3e4..eac83e7c 100644 --- a/yazi-actor/src/mgr/search.rs +++ b/yazi-actor/src/mgr/search.rs @@ -9,7 +9,7 @@ use yazi_macro::{act, succ}; use yazi_parser::{VoidOpt, mgr::{CdSource, SearchOpt, SearchOptVia}}; use yazi_plugin::external; use yazi_proxy::{InputProxy, MgrProxy}; -use yazi_shared::data::Data; +use yazi_shared::{data::Data, url::UrlLike}; use crate::{Actor, Ctx}; diff --git a/yazi-actor/src/mgr/stash.rs b/yazi-actor/src/mgr/stash.rs index eb1bd502..33f7a3a9 100644 --- a/yazi-actor/src/mgr/stash.rs +++ b/yazi-actor/src/mgr/stash.rs @@ -2,7 +2,7 @@ use anyhow::Result; use yazi_dds::spark::SparkKind; use yazi_macro::succ; use yazi_parser::mgr::StashOpt; -use yazi_shared::{Source, data::Data, url::AsUrl}; +use yazi_shared::{Source, data::Data, url::{AsUrl, UrlLike}}; use crate::{Actor, Ctx}; @@ -14,7 +14,7 @@ impl Actor for Stash { const NAME: &str = "stash"; fn act(cx: &mut Ctx, opt: Self::Options) -> Result { - if opt.target.is_regular() { + if opt.target.is_internal() { cx.tab_mut().backstack.push(opt.target.as_url()); } diff --git a/yazi-actor/src/mgr/tab_create.rs b/yazi-actor/src/mgr/tab_create.rs index 2461f6e2..bc9263e3 100644 --- a/yazi-actor/src/mgr/tab_create.rs +++ b/yazi-actor/src/mgr/tab_create.rs @@ -3,7 +3,7 @@ use yazi_core::tab::Tab; use yazi_macro::{act, render, succ}; use yazi_parser::mgr::{CdSource, TabCreateOpt}; use yazi_proxy::AppProxy; -use yazi_shared::data::Data; +use yazi_shared::{data::Data, url::UrlLike}; use crate::{Actor, Ctx}; diff --git a/yazi-binding/src/macros.rs b/yazi-binding/src/macros.rs index 9e0bbcb3..e9ff87f2 100644 --- a/yazi-binding/src/macros.rs +++ b/yazi-binding/src/macros.rs @@ -151,7 +151,7 @@ macro_rules! impl_file_fields { ($fields:ident) => { $crate::cached_field!($fields, cha, |_, me| Ok($crate::Cha(me.cha))); $crate::cached_field!($fields, url, |_, me| Ok($crate::Url::new(me.url_owned()))); - $crate::cached_field!($fields, link_to, |_, me| Ok(me.link_to_url().map($crate::Url::new))); + $crate::cached_field!($fields, link_to, |_, me| Ok(me.link_to.as_ref().map($crate::Path::new))); $crate::cached_field!($fields, name, |lua, me| { me.name().map(|s| lua.create_string(s.encoded_bytes())).transpose() diff --git a/yazi-core/src/tab/preview.rs b/yazi-core/src/tab/preview.rs index 3cfd7ec5..cc7143cb 100644 --- a/yazi-core/src/tab/preview.rs +++ b/yazi-core/src/tab/preview.rs @@ -9,7 +9,7 @@ use yazi_fs::{File, Files, FilesOp, cha::Cha}; use yazi_macro::render; use yazi_parser::mgr::PreviewLock; use yazi_plugin::{external::Highlighter, isolate}; -use yazi_shared::{pool::Symbol, url::UrlBuf}; +use yazi_shared::{pool::Symbol, url::{UrlBuf, UrlLike}}; use yazi_vfs::{VfsFiles, VfsFilesOp}; #[derive(Default)] diff --git a/yazi-fs/src/file.rs b/yazi-fs/src/file.rs index 399ca4c0..dbf067b4 100644 --- a/yazi-fs/src/file.rs +++ b/yazi-fs/src/file.rs @@ -1,6 +1,6 @@ use std::{hash::{Hash, Hasher}, ops::Deref, path::Path}; -use yazi_shared::{loc::Loc, path::{PathBufDyn, PathDyn, PathLike}, strand::Strand, url::{Url, UrlBuf, UrlLike}}; +use yazi_shared::{path::{PathBufDyn, PathDyn}, strand::Strand, url::{UrlBuf, UrlLike}}; use crate::cha::{Cha, ChaType}; @@ -47,23 +47,6 @@ impl File { #[inline] pub fn stem(&self) -> Option> { self.url.stem() } - - pub fn link_to_url(&self) -> Option> { - let to = self.link_to.as_ref()?; - let kind = self.url.kind(); - Some(match &self.url { - UrlBuf::Regular(_) => Url::Regular(Loc::bare(to.as_os().ok()?)), - UrlBuf::Search { domain, .. } => { - Url::Search { loc: Loc::saturated(to.as_os().ok()?, kind), domain } - } - UrlBuf::Archive { domain, .. } => { - Url::Archive { loc: Loc::saturated(to.as_os().ok()?, kind), domain } - } - UrlBuf::Sftp { domain, .. } => { - Url::Sftp { loc: Loc::saturated(to.as_unix().ok()?, kind), domain } - } - }) - } } impl Hash for File { diff --git a/yazi-parser/src/mgr/cd.rs b/yazi-parser/src/mgr/cd.rs index ee83f606..73752618 100644 --- a/yazi-parser/src/mgr/cd.rs +++ b/yazi-parser/src/mgr/cd.rs @@ -55,6 +55,7 @@ pub enum CdSource { Reveal, Enter, Leave, + Follow, Forward, Back, Escape, diff --git a/yazi-plugin/preset/components/tasks.lua b/yazi-plugin/preset/components/tasks.lua index 1976b72e..9ee4f185 100644 --- a/yazi-plugin/preset/components/tasks.lua +++ b/yazi-plugin/preset/components/tasks.lua @@ -63,9 +63,13 @@ end function Tasks:icon(snap) if snap.prog.kind == "FilePaste" then - return " " + return snap.name:find("Copy ", 1, true) == 1 and " " or " " elseif snap.prog.kind == "FileDelete" then return " " + elseif snap.prog.kind == "FileDownload" then + return " " + elseif snap.prog.kind == "FileUpload" then + return " " else return " " end @@ -73,7 +77,7 @@ end function Tasks:progress_redraw(snap, y) local kind = snap.prog.kind - if kind == "FilePaste" or kind == "FileDelete" then + if kind == "FilePaste" or kind == "FileDelete" or kind == "FileDownload" or kind == "FileUpload" then local percent if snap.success then percent = "Cleaning…" diff --git a/yazi-shared/src/url/buf.rs b/yazi-shared/src/url/buf.rs index b21688bc..3acfca56 100644 --- a/yazi-shared/src/url/buf.rs +++ b/yazi-shared/src/url/buf.rs @@ -3,7 +3,7 @@ use std::{borrow::Cow, fmt::{Debug, Formatter}, hash::{Hash, Hasher}, path::{Pat use anyhow::Result; use serde::{Deserialize, Serialize}; -use crate::{loc::LocBuf, path::{PathBufDyn, PathDynError, SetNameError}, pool::{InternStr, Pool, Symbol}, scheme::{Scheme, SchemeKind}, strand::AsStrand, url::{AsUrl, Url, UrlCow, UrlLike}}; +use crate::{loc::LocBuf, path::{PathBufDyn, PathDynError, SetNameError}, pool::{InternStr, Pool, Symbol}, scheme::Scheme, strand::AsStrand, url::{AsUrl, Url, UrlCow, UrlLike}}; #[derive(Clone, Eq)] pub enum UrlBuf { @@ -171,10 +171,6 @@ impl UrlBuf { } impl UrlBuf { - // --- Regular - #[inline] - pub fn is_regular(&self) -> bool { self.as_url().is_regular() } - #[inline] pub fn to_regular(&self) -> Result { Ok(self.as_url().as_regular()?.into()) } @@ -183,10 +179,6 @@ impl UrlBuf { Ok(Self::Regular(self.into_loc().into_os()?.into())) } - // --- Search - #[inline] - pub fn is_search(&self) -> bool { self.kind() == SchemeKind::Search } - #[inline] pub fn to_search(&self, domain: impl AsRef) -> Result { Ok(Self::Search { @@ -202,20 +194,6 @@ impl UrlBuf { domain: Pool::::intern(domain), }) } - - // --- Archive - #[inline] - pub fn is_archive(&self) -> bool { self.kind() == SchemeKind::Archive } - - // --- Internal - #[inline] - pub fn is_internal(&self) -> bool { - match self.kind() { - SchemeKind::Regular | SchemeKind::Sftp => true, - SchemeKind::Search => !self.uri().is_empty(), - SchemeKind::Archive => false, - } - } } impl Debug for UrlBuf { diff --git a/yazi-shared/src/url/cow.rs b/yazi-shared/src/url/cow.rs index 2abf6bf6..7d9a0c5a 100644 --- a/yazi-shared/src/url/cow.rs +++ b/yazi-shared/src/url/cow.rs @@ -249,11 +249,6 @@ impl<'a> UrlCow<'a> { pub fn to_owned(&self) -> UrlBuf { self.as_url().into() } } -impl UrlCow<'_> { - #[inline] - pub fn is_regular(&self) -> bool { self.as_url().is_regular() } -} - impl Serialize for UrlCow<'_> { fn serialize(&self, serializer: S) -> Result where diff --git a/yazi-shared/src/url/like.rs b/yazi-shared/src/url/like.rs index 46c3544f..d9c0574c 100644 --- a/yazi-shared/src/url/like.rs +++ b/yazi-shared/src/url/like.rs @@ -28,6 +28,14 @@ where fn is_absolute(&self) -> bool { self.as_url().is_absolute() } + fn is_archive(&self) -> bool { self.as_url().is_archive() } + + fn is_internal(&self) -> bool { self.as_url().is_internal() } + + fn is_regular(&self) -> bool { self.as_url().is_regular() } + + fn is_search(&self) -> bool { self.as_url().is_search() } + fn kind(&self) -> SchemeKind { self.as_url().kind() } fn loc(&self) -> PathDyn<'_> { self.as_url().loc() } diff --git a/yazi-shared/src/url/url.rs b/yazi-shared/src/url/url.rs index bd971a85..a815670a 100644 --- a/yazi-shared/src/url/url.rs +++ b/yazi-shared/src/url/url.rs @@ -112,6 +112,18 @@ impl<'a> Url<'a> { #[inline] pub fn is_absolute(self) -> bool { self.loc().is_absolute() } + #[inline] + pub fn is_archive(self) -> bool { matches!(self, Self::Archive { .. }) } + + #[inline] + pub fn is_internal(self) -> bool { + match self { + Self::Regular(_) | Self::Sftp { .. } => true, + Self::Search { .. } => !self.uri().is_empty(), + Self::Archive { .. } => false, + } + } + #[inline] pub fn is_regular(self) -> bool { matches!(self, Self::Regular(_)) } @@ -119,7 +131,7 @@ impl<'a> Url<'a> { pub fn is_search(self) -> bool { matches!(self, Self::Search { .. }) } #[inline] - pub fn kind(&self) -> SchemeKind { + pub fn kind(self) -> SchemeKind { match self { Self::Regular(_) => SchemeKind::Regular, Self::Search { .. } => SchemeKind::Search, diff --git a/yazi-vfs/src/files.rs b/yazi-vfs/src/files.rs index 6da53277..ed57afdf 100644 --- a/yazi-vfs/src/files.rs +++ b/yazi-vfs/src/files.rs @@ -38,7 +38,7 @@ impl VfsFiles for Files { async fn from_dir_bulk(dir: &UrlBuf) -> std::io::Result> { let mut it = provider::read_dir(dir).await?; - let mut entries = Vec::with_capacity(5000); + let mut entries = Vec::new(); while let Ok(Some(entry)) = it.next().await { entries.push(entry); }