mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-21 23:01:05 +00:00
fix!: open command doesn't work under empty directories (#3226)
This commit is contained in:
parent
d8b0425a10
commit
149a5feffb
45 changed files with 277 additions and 280 deletions
52
Cargo.lock
generated
52
Cargo.lock
generated
|
|
@ -115,9 +115,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.11"
|
||||
version = "1.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd"
|
||||
checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
|
|
@ -1917,9 +1917,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "lua-src"
|
||||
version = "548.1.1"
|
||||
version = "548.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00bc4bd1f1d5c65b30717333cbec4fa7aa378978940a1bca62f404498d423233"
|
||||
checksum = "bdc4e1aff422ad5f08cffb4719603dcdbc2be2307f4c1510d7aab74b7fa88ca8"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
|
@ -2003,9 +2003,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "mlua"
|
||||
version = "0.11.3"
|
||||
version = "0.11.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b3dd94c3c4dea0049b22296397040840a8f6b5b5229f438434ba82df402b42d"
|
||||
checksum = "9be1c2bfc684b8a228fbaebf954af7a47a98ec27721986654a4cc2c40a20cc7e"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bstr",
|
||||
|
|
@ -2341,9 +2341,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "ordered-float"
|
||||
version = "5.0.0"
|
||||
version = "5.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2c1f9f56e534ac6a9b8a4600bdf0f530fb393b5f393e7b4d03489c3cf0c3f01"
|
||||
checksum = "7f4779c6901a562440c3786d08192c6fbda7c1c2060edd10006b05ee35d10f2d"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
"rand 0.8.5",
|
||||
|
|
@ -2732,9 +2732,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.40"
|
||||
version = "1.0.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
|
||||
checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
|
@ -2909,7 +2909,7 @@ checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
|
|||
dependencies = [
|
||||
"getrandom 0.2.16",
|
||||
"libredox",
|
||||
"thiserror 2.0.16",
|
||||
"thiserror 2.0.17",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3517,7 +3517,7 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"thiserror 2.0.16",
|
||||
"thiserror 2.0.17",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
|
|
@ -3557,11 +3557,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.16"
|
||||
version = "2.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0"
|
||||
checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8"
|
||||
dependencies = [
|
||||
"thiserror-impl 2.0.16",
|
||||
"thiserror-impl 2.0.17",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -3577,9 +3577,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.16"
|
||||
version = "2.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960"
|
||||
checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -3884,9 +3884,9 @@ checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c"
|
|||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.18.0"
|
||||
version = "1.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
|
||||
checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
|
|
@ -4764,7 +4764,7 @@ dependencies = [
|
|||
"anyhow",
|
||||
"hashbrown 0.16.0",
|
||||
"mlua",
|
||||
"ordered-float 5.0.0",
|
||||
"ordered-float 5.1.0",
|
||||
"parking_lot",
|
||||
"paste",
|
||||
"serde",
|
||||
|
|
@ -4879,7 +4879,7 @@ dependencies = [
|
|||
"crossterm 0.29.0",
|
||||
"hashbrown 0.16.0",
|
||||
"mlua",
|
||||
"ordered-float 5.0.0",
|
||||
"ordered-float 5.1.0",
|
||||
"serde",
|
||||
"tokio",
|
||||
"yazi-binding",
|
||||
|
|
@ -4957,7 +4957,7 @@ dependencies = [
|
|||
"libc",
|
||||
"lru 0.16.1",
|
||||
"mlua",
|
||||
"ordered-float 5.0.0",
|
||||
"ordered-float 5.1.0",
|
||||
"parking_lot",
|
||||
"scopeguard",
|
||||
"serde",
|
||||
|
|
@ -4998,7 +4998,7 @@ dependencies = [
|
|||
"hashbrown 0.16.0",
|
||||
"libc",
|
||||
"memchr",
|
||||
"ordered-float 5.0.0",
|
||||
"ordered-float 5.1.0",
|
||||
"parking_lot",
|
||||
"percent-encoding",
|
||||
"serde",
|
||||
|
|
@ -5031,9 +5031,7 @@ dependencies = [
|
|||
"hashbrown 0.16.0",
|
||||
"parking_lot",
|
||||
"russh",
|
||||
"serde",
|
||||
"tokio",
|
||||
"toml 0.9.7",
|
||||
"tracing",
|
||||
"uzers",
|
||||
"yazi-config",
|
||||
|
|
@ -5105,9 +5103,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "zeroize"
|
||||
version = "1.8.1"
|
||||
version = "1.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
|
||||
checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
|
||||
|
||||
[[package]]
|
||||
name = "zune-core"
|
||||
|
|
|
|||
|
|
@ -35,9 +35,9 @@ hashbrown = { version = "0.16.0", features = [ "serde" ] }
|
|||
indexmap = { version = "2.11.4", features = [ "serde" ] }
|
||||
libc = "0.2.176"
|
||||
lru = "0.16.1"
|
||||
mlua = { version = "0.11.3", features = [ "anyhow", "async", "error-send", "lua54", "macros", "serde" ] }
|
||||
mlua = { version = "0.11.4", features = [ "anyhow", "async", "error-send", "lua54", "macros", "serde" ] }
|
||||
objc = "0.2.7"
|
||||
ordered-float = { version = "5.0.0", features = [ "serde" ] }
|
||||
ordered-float = { version = "5.1.0", features = [ "serde" ] }
|
||||
parking_lot = "0.12.4"
|
||||
paste = "1.0.15"
|
||||
ratatui = { version = "0.29.0", features = [ "unstable-rendered-line-info", "unstable-widget-ref" ] }
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use yazi_fs::File;
|
|||
use yazi_macro::{act, succ};
|
||||
use yazi_parser::mgr::{OpenDoOpt, OpenOpt};
|
||||
use yazi_proxy::MgrProxy;
|
||||
use yazi_shared::{data::Data, url::UrlCow};
|
||||
use yazi_shared::data::Data;
|
||||
use yazi_vfs::VfsFile;
|
||||
|
||||
use crate::{Actor, Ctx, mgr::Quit};
|
||||
|
|
@ -17,27 +17,28 @@ impl Actor for Open {
|
|||
const NAME: &str = "open";
|
||||
|
||||
fn act(cx: &mut Ctx, mut opt: Self::Options) -> Result<Data> {
|
||||
act!(mgr:escape_visual, cx)?;
|
||||
|
||||
let Some(hovered) = cx.hovered().map(|h| h.url_owned()).map(UrlCow::from) else { succ!() };
|
||||
|
||||
if !opt.interactive && ARGS.chooser_file.is_some() {
|
||||
succ!(if !opt.targets.is_empty() {
|
||||
Quit::with_selected(opt.targets)
|
||||
} else if opt.hovered {
|
||||
Quit::with_selected([hovered])
|
||||
Quit::with_selected(cx.hovered().map(|h| &h.url))
|
||||
} else {
|
||||
act!(mgr:escape_visual, cx)?;
|
||||
Quit::with_selected(cx.tab().selected_or_hovered())
|
||||
});
|
||||
}
|
||||
|
||||
if opt.targets.is_empty() {
|
||||
opt.targets = if opt.hovered {
|
||||
vec![hovered.clone()]
|
||||
cx.hovered().map(|h| vec![h.url.clone().into()]).unwrap_or_default()
|
||||
} else {
|
||||
act!(mgr:escape_visual, cx)?;
|
||||
cx.tab().selected_or_hovered().cloned().map(Into::into).collect()
|
||||
};
|
||||
}
|
||||
if opt.targets.is_empty() {
|
||||
succ!();
|
||||
}
|
||||
|
||||
let todo: Vec<_> = opt
|
||||
.targets
|
||||
|
|
@ -49,7 +50,7 @@ impl Actor for Open {
|
|||
|
||||
let cwd = cx.cwd().clone();
|
||||
if todo.is_empty() {
|
||||
return act!(mgr:open_do, cx, OpenDoOpt { cwd, hovered, targets: opt.targets, interactive: opt.interactive });
|
||||
return act!(mgr:open_do, cx, OpenDoOpt { cwd, targets: opt.targets, interactive: opt.interactive });
|
||||
}
|
||||
|
||||
let scheduler = cx.tasks.scheduler.clone();
|
||||
|
|
@ -61,12 +62,7 @@ impl Actor for Open {
|
|||
}
|
||||
}
|
||||
if scheduler.fetch_mimetype(files).await {
|
||||
MgrProxy::open_do(OpenDoOpt {
|
||||
cwd,
|
||||
hovered,
|
||||
targets: opt.targets,
|
||||
interactive: opt.interactive,
|
||||
});
|
||||
MgrProxy::open_do(OpenDoOpt { cwd, targets: opt.targets, interactive: opt.interactive });
|
||||
}
|
||||
});
|
||||
succ!();
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use yazi_config::{YAZI, popup::PickCfg};
|
|||
use yazi_macro::succ;
|
||||
use yazi_parser::mgr::OpenDoOpt;
|
||||
use yazi_proxy::{PickProxy, TasksProxy};
|
||||
use yazi_shared::data::Data;
|
||||
use yazi_shared::{data::Data, url::UrlCow};
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
||||
|
|
@ -30,7 +30,7 @@ impl Actor for OpenDo {
|
|||
if targets.is_empty() {
|
||||
succ!();
|
||||
} else if !opt.interactive {
|
||||
succ!(cx.tasks.process_from_files(opt.cwd, opt.hovered, targets));
|
||||
succ!(cx.tasks.process_with_selected(opt.cwd, targets));
|
||||
}
|
||||
|
||||
let openers: Vec<_> = YAZI.opener.all(YAZI.open.common(&targets).into_iter());
|
||||
|
|
@ -39,10 +39,10 @@ impl Actor for OpenDo {
|
|||
}
|
||||
|
||||
let pick = PickProxy::show(PickCfg::open(openers.iter().map(|o| o.desc()).collect()));
|
||||
let urls = [opt.hovered].into_iter().chain(targets.into_iter().map(|(u, _)| u)).collect();
|
||||
let urls = [UrlCow::default()].into_iter().chain(targets.into_iter().map(|(u, _)| u)).collect();
|
||||
tokio::spawn(async move {
|
||||
if let Ok(choice) = pick.await {
|
||||
TasksProxy::open_with(Cow::Borrowed(openers[choice]), opt.cwd, urls);
|
||||
TasksProxy::file_open(Cow::Borrowed(openers[choice]), opt.cwd, urls);
|
||||
}
|
||||
});
|
||||
succ!();
|
||||
|
|
|
|||
|
|
@ -77,6 +77,8 @@ impl Quit {
|
|||
s
|
||||
});
|
||||
|
||||
emit!(Quit(EventQuit { selected: Some(paths), ..Default::default() }));
|
||||
if !paths.is_empty() {
|
||||
emit!(Quit(EventQuit { selected: Some(paths), ..Default::default() }));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ impl Actor for SearchStop {
|
|||
succ!();
|
||||
}
|
||||
|
||||
let rep = tab.history.remove_or(&tab.cwd().to_regular());
|
||||
let rep = tab.history.remove_or(tab.cwd().to_regular());
|
||||
drop(mem::replace(&mut tab.current, rep));
|
||||
|
||||
act!(mgr:hidden, cx)?;
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ impl Actor for Shell {
|
|||
return;
|
||||
}
|
||||
|
||||
TasksProxy::open_with(
|
||||
TasksProxy::file_open(
|
||||
Cow::Owned(OpenerRule {
|
||||
run: opt.run.into_owned(),
|
||||
block: opt.block,
|
||||
|
|
|
|||
|
|
@ -5,15 +5,15 @@ use yazi_shared::data::Data;
|
|||
|
||||
use crate::{Actor, Ctx};
|
||||
|
||||
pub struct OpenWith;
|
||||
pub struct FileOpen;
|
||||
|
||||
impl Actor for OpenWith {
|
||||
impl Actor for FileOpen {
|
||||
type Options = OpenWithOpt;
|
||||
|
||||
const NAME: &str = "open_with";
|
||||
const NAME: &str = "file_open";
|
||||
|
||||
fn act(cx: &mut Ctx, opt: Self::Options) -> Result<Data> {
|
||||
succ!(cx.tasks.process_from_opener(
|
||||
succ!(cx.tasks.process_with_opener(
|
||||
opt.cwd,
|
||||
opt.opener,
|
||||
opt.targets.into_iter().map(|u| u.into_os_str2()).collect(),
|
||||
|
|
@ -1 +1 @@
|
|||
yazi_macro::mod_flat!(arrow cancel close inspect open_with process_exec show update_succeed);
|
||||
yazi_macro::mod_flat!(arrow cancel close file_open inspect process_open show update_succeed);
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
use anyhow::Result;
|
||||
use yazi_macro::succ;
|
||||
use yazi_parser::tasks::ProcessExecOpt;
|
||||
use yazi_parser::tasks::ProcessOpenOpt;
|
||||
use yazi_shared::data::Data;
|
||||
|
||||
use crate::{Actor, Ctx};
|
||||
|
||||
pub struct ProcessExec;
|
||||
pub struct ProcessOpen;
|
||||
|
||||
impl Actor for ProcessExec {
|
||||
type Options = ProcessExecOpt;
|
||||
impl Actor for ProcessOpen {
|
||||
type Options = ProcessOpenOpt;
|
||||
|
||||
const NAME: &str = "process_exec";
|
||||
const NAME: &str = "process_open";
|
||||
|
||||
fn act(cx: &mut Ctx, opt: Self::Options) -> Result<Data> {
|
||||
succ!(cx.tasks.scheduler.process_open(opt));
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
use std::ops::Deref;
|
||||
|
||||
use mlua::{AnyUserData, ExternalError, FromLua, Lua, MetaMethod, UserData, UserDataFields, UserDataMethods, UserDataRef, Value};
|
||||
use yazi_shared::{IntoOsStr, url::UrlCow};
|
||||
use yazi_shared::{IntoOsStr, url::{AsUrl, UrlCow}};
|
||||
|
||||
use crate::{Urn, cached_field, deprecate};
|
||||
|
||||
|
|
@ -29,12 +29,16 @@ impl AsRef<yazi_shared::url::UrlBuf> for Url {
|
|||
fn as_ref(&self) -> &yazi_shared::url::UrlBuf { &self.inner }
|
||||
}
|
||||
|
||||
impl From<Url> for yazi_shared::url::UrlBuf {
|
||||
fn from(value: Url) -> Self { value.inner }
|
||||
impl AsUrl for Url {
|
||||
fn as_url(&self) -> yazi_shared::url::Url<'_> { self.inner.as_url() }
|
||||
}
|
||||
|
||||
impl<'a> From<&'a Url> for yazi_shared::url::Url<'a> {
|
||||
fn from(value: &'a Url) -> Self { value.as_url() }
|
||||
impl AsUrl for &Url {
|
||||
fn as_url(&self) -> yazi_shared::url::Url<'_> { self.inner.as_url() }
|
||||
}
|
||||
|
||||
impl From<Url> for yazi_shared::url::UrlBuf {
|
||||
fn from(value: Url) -> Self { value.inner }
|
||||
}
|
||||
|
||||
impl<'a> From<&'a Url> for UrlCow<'a> {
|
||||
|
|
|
|||
|
|
@ -14,4 +14,4 @@ proc-macro = true
|
|||
[dependencies]
|
||||
# External dependencies
|
||||
syn = { version = "2.0.106", features = [ "full" ] }
|
||||
quote = "1.0.40"
|
||||
quote = "1.0.41"
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ impl Open {
|
|||
M: AsRef<str>,
|
||||
{
|
||||
let each: Vec<IndexSet<&str>> = targets
|
||||
.into_iter()
|
||||
.iter()
|
||||
.map(|(u, m)| self.all(u, m).collect::<IndexSet<_>>())
|
||||
.filter(|s| !s.is_empty())
|
||||
.collect();
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::str::FromStr;
|
|||
use anyhow::Result;
|
||||
use globset::GlobBuilder;
|
||||
use serde::Deserialize;
|
||||
use yazi_shared::{scheme::{SchemeCow, SchemeRef}, url::Url};
|
||||
use yazi_shared::{scheme::{SchemeCow, SchemeRef}, url::AsUrl};
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(try_from = "String")]
|
||||
|
|
@ -17,8 +17,8 @@ pub struct Pattern {
|
|||
}
|
||||
|
||||
impl Pattern {
|
||||
pub fn match_url<'a>(&self, url: impl Into<Url<'a>>, is_dir: bool) -> bool {
|
||||
let url = url.into();
|
||||
pub fn match_url(&self, url: impl AsUrl, is_dir: bool) -> bool {
|
||||
let url = url.as_url();
|
||||
|
||||
if is_dir != self.is_dir {
|
||||
return false;
|
||||
|
|
@ -126,7 +126,7 @@ mod tests {
|
|||
use super::*;
|
||||
|
||||
fn matches(glob: &str, url: &str) -> bool {
|
||||
Pattern::from_str(glob).unwrap().match_url(&UrlCow::try_from(url).unwrap(), false)
|
||||
Pattern::from_str(glob).unwrap().match_url(UrlCow::try_from(url).unwrap(), false)
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use hashbrown::HashMap;
|
||||
use yazi_shared::url::{Url, UrlBuf};
|
||||
use yazi_shared::url::{AsUrl, UrlBuf};
|
||||
|
||||
use super::Folder;
|
||||
|
||||
|
|
@ -19,8 +19,8 @@ impl DerefMut for History {
|
|||
}
|
||||
|
||||
impl History {
|
||||
pub fn remove_or<'a>(&mut self, url: impl Into<Url<'a>>) -> Folder {
|
||||
let url = url.into();
|
||||
pub fn remove_or(&mut self, url: impl AsUrl) -> Folder {
|
||||
let url = url.as_url();
|
||||
self.0.remove(&url).unwrap_or_else(|| Folder::from(url))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,53 +2,47 @@ use std::{borrow::Cow, ffi::OsStr, mem};
|
|||
|
||||
use hashbrown::HashMap;
|
||||
use yazi_config::{YAZI, opener::OpenerRule};
|
||||
use yazi_parser::tasks::ProcessExecOpt;
|
||||
use yazi_parser::tasks::ProcessOpenOpt;
|
||||
use yazi_shared::url::{UrlBuf, UrlCow};
|
||||
|
||||
use super::Tasks;
|
||||
|
||||
impl Tasks {
|
||||
pub fn process_from_files(
|
||||
&self,
|
||||
cwd: UrlBuf,
|
||||
hovered: UrlCow<'static>,
|
||||
targets: Vec<(UrlCow<'static>, &str)>,
|
||||
) {
|
||||
pub fn process_with_selected(&self, cwd: UrlBuf, targets: Vec<(UrlCow<'static>, &str)>) {
|
||||
let mut openers = HashMap::new();
|
||||
for (url, mime) in targets {
|
||||
if let Some(opener) = YAZI.opener.first(YAZI.open.all(&url, mime)) {
|
||||
openers.entry(opener).or_insert_with(|| vec![hovered.clone()]).push(url);
|
||||
openers
|
||||
.entry(opener)
|
||||
.or_insert_with(|| vec![OsStr::new("").into()])
|
||||
.push(url.into_os_str2());
|
||||
}
|
||||
}
|
||||
for (opener, args) in openers {
|
||||
self.process_from_opener(
|
||||
cwd.clone(),
|
||||
Cow::Borrowed(opener),
|
||||
args.into_iter().map(|u| u.into_os_str2()).collect(),
|
||||
);
|
||||
self.process_with_opener(cwd.clone(), Cow::Borrowed(opener), args);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process_from_opener(
|
||||
pub fn process_with_opener(
|
||||
&self,
|
||||
cwd: UrlBuf,
|
||||
opener: Cow<'static, OpenerRule>,
|
||||
mut args: Vec<Cow<'static, OsStr>>,
|
||||
) {
|
||||
if opener.spread {
|
||||
self.scheduler.process_open(ProcessExecOpt { cwd, opener, args, done: None });
|
||||
self.scheduler.process_open(ProcessOpenOpt { cwd, opener, args, done: None });
|
||||
return;
|
||||
}
|
||||
if args.is_empty() {
|
||||
return;
|
||||
}
|
||||
if args.len() == 2 {
|
||||
self.scheduler.process_open(ProcessExecOpt { cwd, opener, args, done: None });
|
||||
self.scheduler.process_open(ProcessOpenOpt { cwd, opener, args, done: None });
|
||||
return;
|
||||
}
|
||||
let hovered = mem::take(&mut args[0]);
|
||||
for target in args.into_iter().skip(1) {
|
||||
self.scheduler.process_open(ProcessExecOpt {
|
||||
self.scheduler.process_open(ProcessOpenOpt {
|
||||
cwd: cwd.clone(),
|
||||
opener: opener.clone(),
|
||||
args: vec![hovered.clone(), target],
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ pub enum Spark<'a> {
|
|||
SpotCopy(yazi_parser::spot::CopyOpt),
|
||||
|
||||
// Tasks
|
||||
TasksProcessExec(yazi_parser::tasks::ProcessExecOpt),
|
||||
TasksProcessOpen(yazi_parser::tasks::ProcessOpenOpt),
|
||||
TasksUpdateSucceed(yazi_parser::tasks::UpdateSucceedOpt),
|
||||
|
||||
// Which
|
||||
|
|
@ -231,7 +231,7 @@ impl<'a> IntoLua for Spark<'a> {
|
|||
Self::SpotCopy(b) => b.into_lua(lua),
|
||||
|
||||
// Tasks
|
||||
Self::TasksProcessExec(b) => b.into_lua(lua),
|
||||
Self::TasksProcessOpen(b) => b.into_lua(lua),
|
||||
Self::TasksUpdateSucceed(b) => b.into_lua(lua),
|
||||
|
||||
// Which
|
||||
|
|
@ -324,7 +324,7 @@ try_from_spark!(notify::TickOpt, notify:tick);
|
|||
try_from_spark!(pick::CloseOpt, pick:close);
|
||||
try_from_spark!(pick::ShowOpt, pick:show);
|
||||
try_from_spark!(spot::CopyOpt, spot:copy);
|
||||
try_from_spark!(tasks::ProcessExecOpt, tasks:process_exec);
|
||||
try_from_spark!(tasks::ProcessOpenOpt, tasks:process_open);
|
||||
try_from_spark!(tasks::UpdateSucceedOpt, tasks:update_succeed);
|
||||
try_from_spark!(which::CallbackOpt, which:callback);
|
||||
try_from_spark!(which::ShowOpt, which:show);
|
||||
|
|
|
|||
|
|
@ -164,8 +164,8 @@ impl<'a> Executor<'a> {
|
|||
on!(arrow);
|
||||
on!(inspect);
|
||||
on!(cancel);
|
||||
on!(open_with);
|
||||
on!(process_exec);
|
||||
on!(file_open);
|
||||
on!(process_open);
|
||||
|
||||
match cmd.name.as_ref() {
|
||||
// Help
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::{ffi::OsStr, fs::Metadata, ops::Deref, time::{Duration, SystemTime, UNI
|
|||
|
||||
use anyhow::bail;
|
||||
use yazi_macro::{unix_either, win_either};
|
||||
use yazi_shared::url::Url;
|
||||
use yazi_shared::url::AsUrl;
|
||||
|
||||
use super::ChaKind;
|
||||
use crate::cha::{ChaMode, ChaType};
|
||||
|
|
@ -52,15 +52,15 @@ impl Cha {
|
|||
Self::from_bare(&meta).attach(ChaKind::hidden(name, &meta))
|
||||
}
|
||||
|
||||
pub fn from_dummy<'a, U>(_url: U, r#type: Option<ChaType>) -> Self
|
||||
pub fn from_dummy<U>(_url: U, r#type: Option<ChaType>) -> Self
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
U: AsUrl,
|
||||
{
|
||||
let mut kind = ChaKind::DUMMY;
|
||||
let mode = r#type.map(ChaMode::from_bare).unwrap_or_default();
|
||||
|
||||
#[cfg(unix)]
|
||||
if _url.into().urn().is_hidden() {
|
||||
if _url.as_url().urn().is_hidden() {
|
||||
kind |= ChaKind::HIDDEN;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use std::{io, path::{Path, PathBuf}};
|
||||
|
||||
use yazi_shared::url::{Url, UrlCow};
|
||||
use yazi_shared::url::{AsUrl, UrlCow};
|
||||
|
||||
use crate::{cha::Cha, path::absolute_url, provider::Provider};
|
||||
|
||||
|
|
@ -12,11 +12,11 @@ impl Provider for Local {
|
|||
type Gate = super::Gate;
|
||||
type ReadDir = super::ReadDir;
|
||||
|
||||
async fn absolute<'a, U>(&self, url: U) -> io::Result<UrlCow<'a>>
|
||||
async fn absolute<'a, U>(&self, url: &'a U) -> io::Result<UrlCow<'a>>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
U: AsUrl,
|
||||
{
|
||||
let url: Url = url.into();
|
||||
let url = url.as_url();
|
||||
if url.scheme.is_virtual() {
|
||||
Err(io::Error::new(io::ErrorKind::InvalidInput, "Not a local URL"))
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::{borrow::Cow, ffi::OsStr, io, path::{Path, PathBuf}};
|
|||
|
||||
use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt};
|
||||
use yazi_macro::ok_or_not_found;
|
||||
use yazi_shared::{scheme::SchemeRef, url::{Url, UrlCow}};
|
||||
use yazi_shared::{scheme::SchemeRef, url::{AsUrl, UrlCow}};
|
||||
|
||||
use crate::cha::{Cha, ChaType};
|
||||
|
||||
|
|
@ -11,9 +11,9 @@ pub trait Provider {
|
|||
type Gate: FileBuilder<File = Self::File>;
|
||||
type ReadDir: DirReader;
|
||||
|
||||
fn absolute<'a, U>(&self, url: U) -> impl Future<Output = io::Result<UrlCow<'a>>>
|
||||
fn absolute<'a, U>(&self, url: &'a U) -> impl Future<Output = io::Result<UrlCow<'a>>>
|
||||
where
|
||||
U: Into<Url<'a>>;
|
||||
U: AsUrl;
|
||||
|
||||
fn canonicalize<P>(&self, path: P) -> impl Future<Output = io::Result<PathBuf>>
|
||||
where
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ use yazi_shared::{event::CmdCow, url::{UrlBuf, UrlCow}};
|
|||
#[derive(Debug, Default)]
|
||||
pub struct OpenDoOpt {
|
||||
pub cwd: UrlBuf,
|
||||
pub hovered: UrlCow<'static>,
|
||||
pub targets: Vec<UrlCow<'static>>,
|
||||
pub interactive: bool,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
yazi_macro::mod_flat!(process_exec update_succeed);
|
||||
yazi_macro::mod_flat!(process_open update_succeed);
|
||||
|
|
|
|||
|
|
@ -8,25 +8,25 @@ use yazi_shared::{event::CmdCow, url::UrlBuf};
|
|||
|
||||
// --- Exec
|
||||
#[derive(Debug)]
|
||||
pub struct ProcessExecOpt {
|
||||
pub struct ProcessOpenOpt {
|
||||
pub cwd: UrlBuf,
|
||||
pub opener: Cow<'static, OpenerRule>,
|
||||
pub args: Vec<Cow<'static, OsStr>>,
|
||||
pub done: Option<oneshot::Sender<()>>,
|
||||
}
|
||||
|
||||
impl TryFrom<CmdCow> for ProcessExecOpt {
|
||||
impl TryFrom<CmdCow> for ProcessOpenOpt {
|
||||
type Error = anyhow::Error;
|
||||
|
||||
fn try_from(mut c: CmdCow) -> Result<Self, Self::Error> {
|
||||
c.take_any("option").ok_or_else(|| anyhow!("Missing 'option' in ProcessExecOpt"))
|
||||
c.take_any("option").ok_or_else(|| anyhow!("Missing 'option' in ProcessOpenOpt"))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromLua for ProcessExecOpt {
|
||||
impl FromLua for ProcessOpenOpt {
|
||||
fn from_lua(_: Value, _: &Lua) -> mlua::Result<Self> { Err("unsupported".into_lua_err()) }
|
||||
}
|
||||
|
||||
impl IntoLua for ProcessExecOpt {
|
||||
impl IntoLua for ProcessOpenOpt {
|
||||
fn into_lua(self, _: &Lua) -> mlua::Result<Value> { Err("unsupported".into_lua_err()) }
|
||||
}
|
||||
|
|
@ -3,14 +3,14 @@ use std::{borrow::Cow, ffi::OsStr};
|
|||
use tokio::sync::oneshot;
|
||||
use yazi_config::opener::OpenerRule;
|
||||
use yazi_macro::{emit, relay};
|
||||
use yazi_parser::{mgr::OpenWithOpt, tasks::ProcessExecOpt};
|
||||
use yazi_parser::{mgr::OpenWithOpt, tasks::ProcessOpenOpt};
|
||||
use yazi_shared::url::{UrlBuf, UrlCow};
|
||||
|
||||
pub struct TasksProxy;
|
||||
|
||||
impl TasksProxy {
|
||||
pub fn open_with(opener: Cow<'static, OpenerRule>, cwd: UrlBuf, targets: Vec<UrlCow<'static>>) {
|
||||
emit!(Call(relay!(tasks:open_with).with_any("option", OpenWithOpt { opener, cwd, targets })));
|
||||
pub fn file_open(opener: Cow<'static, OpenerRule>, cwd: UrlBuf, targets: Vec<UrlCow<'static>>) {
|
||||
emit!(Call(relay!(tasks:file_open).with_any("option", OpenWithOpt { opener, cwd, targets })));
|
||||
}
|
||||
|
||||
pub async fn process_exec(
|
||||
|
|
@ -19,7 +19,7 @@ impl TasksProxy {
|
|||
args: Vec<Cow<'static, OsStr>>,
|
||||
) {
|
||||
let (tx, rx) = oneshot::channel();
|
||||
emit!(Call(relay!(tasks:process_exec).with_any("option", ProcessExecOpt {
|
||||
emit!(Call(relay!(tasks:process_open).with_any("option", ProcessOpenOpt {
|
||||
cwd,
|
||||
opener,
|
||||
args,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use tracing::warn;
|
|||
use yazi_config::YAZI;
|
||||
use yazi_fs::{cha::Cha, ok_or_not_found, path::{path_relative_to, skip_url}, provider::{DirReader, FileHolder}};
|
||||
use yazi_macro::ok_or_not_found;
|
||||
use yazi_shared::url::{Url, UrlBuf, UrlCow};
|
||||
use yazi_shared::url::{AsUrl, UrlBuf, UrlCow};
|
||||
use yazi_vfs::{VfsCha, copy_with_progress, maybe_exists, provider::{self, DirEntry}};
|
||||
|
||||
use super::{FileInDelete, FileInHardlink, FileInLink, FileInPaste, FileInTrash};
|
||||
|
|
@ -289,8 +289,8 @@ impl File {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
async fn cha<'a>(url: impl Into<Url<'a>>, follow: bool) -> io::Result<Cha> {
|
||||
let url = url.into();
|
||||
async fn cha(url: impl AsUrl, follow: bool) -> io::Result<Cha> {
|
||||
let url = url.as_url();
|
||||
let cha = provider::symlink_metadata(url).await?;
|
||||
Ok(if follow { Cha::from_follow(url, cha).await } else { cha })
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use tokio::{select, sync::{mpsc::{self, UnboundedReceiver}, oneshot}, task::Join
|
|||
use yazi_config::{YAZI, plugin::{Fetcher, Preloader}};
|
||||
use yazi_dds::Pump;
|
||||
use yazi_fs::FsUrl;
|
||||
use yazi_parser::{app::PluginOpt, tasks::ProcessExecOpt};
|
||||
use yazi_parser::{app::PluginOpt, tasks::ProcessOpenOpt};
|
||||
use yazi_proxy::TasksProxy;
|
||||
use yazi_shared::{Id, Throttle, url::UrlBuf};
|
||||
use yazi_vfs::{must_be_dir, provider, unique_name};
|
||||
|
|
@ -310,7 +310,7 @@ impl Scheduler {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn process_open(&self, ProcessExecOpt { cwd, opener, args, done }: ProcessExecOpt) {
|
||||
pub fn process_open(&self, ProcessOpenOpt { cwd, opener, args, done }: ProcessOpenOpt) {
|
||||
let name = {
|
||||
let args = args.iter().map(|a| a.to_string_lossy()).collect::<Vec<_>>().join(" ");
|
||||
if args.is_empty() {
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ impl From<Error> for std::io::Error {
|
|||
Error::IO(e) => e,
|
||||
Error::Serde(e) => Self::new(std::io::ErrorKind::InvalidData, e),
|
||||
Error::Status(status) => match status.code {
|
||||
responses::StatusCode::Ok => Self::new(std::io::ErrorKind::Other, "unexpected OK"),
|
||||
responses::StatusCode::Ok => Self::other("unexpected OK"),
|
||||
responses::StatusCode::Eof => Self::from(std::io::ErrorKind::UnexpectedEof),
|
||||
responses::StatusCode::NoSuchFile => Self::from(std::io::ErrorKind::NotFound),
|
||||
responses::StatusCode::PermissionDenied => Self::from(std::io::ErrorKind::PermissionDenied),
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ impl Operator {
|
|||
status.into()
|
||||
}
|
||||
|
||||
pub async fn fsetstat<'a>(&self, handle: &str, attrs: &'a Attrs) -> Result<(), Error> {
|
||||
pub async fn fsetstat(&self, handle: &str, attrs: &Attrs) -> Result<(), Error> {
|
||||
let status: responses::Status = self.send(requests::FSetStat::new(handle, attrs)).await?;
|
||||
status.into()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ impl Cmd {
|
|||
T: TryFrom<&'a Data>,
|
||||
T::Error: Into<anyhow::Error>,
|
||||
{
|
||||
self.get(0).map_err(Into::into)
|
||||
self.get(0)
|
||||
}
|
||||
|
||||
pub fn second<'a, T>(&'a self) -> Result<T>
|
||||
|
|
@ -107,7 +107,7 @@ impl Cmd {
|
|||
T: TryFrom<&'a Data>,
|
||||
T::Error: Into<anyhow::Error>,
|
||||
{
|
||||
self.get(1).map_err(Into::into)
|
||||
self.get(1)
|
||||
}
|
||||
|
||||
pub fn seq<'a, T>(&'a self) -> Vec<T>
|
||||
|
|
@ -128,7 +128,7 @@ impl Cmd {
|
|||
}
|
||||
|
||||
// --- Take
|
||||
pub fn take<'a, T>(&mut self, name: impl Into<DataKey>) -> Result<T>
|
||||
pub fn take<T>(&mut self, name: impl Into<DataKey>) -> Result<T>
|
||||
where
|
||||
T: TryFrom<Data>,
|
||||
T::Error: Into<anyhow::Error>,
|
||||
|
|
@ -140,7 +140,7 @@ impl Cmd {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn take_first<'a, T>(&mut self) -> Result<T>
|
||||
pub fn take_first<T>(&mut self) -> Result<T>
|
||||
where
|
||||
T: TryFrom<Data>,
|
||||
T::Error: Into<anyhow::Error>,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ use std::{borrow::Cow, ffi::OsStr, fmt::{Debug, Formatter}, hash::BuildHasher, p
|
|||
use anyhow::Result;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{loc::LocBuf, pool::Pool, scheme::{Scheme, SchemeRef}, url::{Components, Display, Encode, EncodeTilded, Uri, Url, UrlCow, Urn}};
|
||||
use crate::{loc::LocBuf, pool::Pool, scheme::{Scheme, SchemeRef}, url::{AsUrl, Components, Display, Encode, EncodeTilded, Uri, Url, UrlCow, Urn}};
|
||||
|
||||
#[derive(Clone, Default, Eq, Hash, PartialEq)]
|
||||
pub struct UrlBuf {
|
||||
|
|
@ -108,18 +108,16 @@ impl UrlBuf {
|
|||
pub fn parent(&self) -> Option<Url<'_>> { self.as_url().parent() }
|
||||
|
||||
#[inline]
|
||||
pub fn starts_with<'a>(&self, base: impl Into<Url<'a>>) -> bool {
|
||||
self.as_url().starts_with(base)
|
||||
}
|
||||
pub fn starts_with(&self, base: impl AsUrl) -> bool { self.as_url().starts_with(base) }
|
||||
|
||||
#[inline]
|
||||
pub fn ends_with<'a>(&self, child: impl Into<Url<'a>>) -> bool { self.as_url().ends_with(child) }
|
||||
pub fn ends_with(&self, child: impl AsUrl) -> bool { self.as_url().ends_with(child) }
|
||||
|
||||
pub fn strip_prefix<'a>(&self, base: impl Into<Url<'a>>) -> Option<&Urn> {
|
||||
pub fn strip_prefix(&self, base: impl AsUrl) -> Option<&Urn> {
|
||||
use Scheme as S;
|
||||
use SchemeRef as T;
|
||||
|
||||
let base = base.into();
|
||||
let base = base.as_url();
|
||||
let prefix = self.loc.strip_prefix(base.loc).ok()?;
|
||||
|
||||
Some(Urn::new(match (&self.scheme, base.scheme) {
|
||||
|
|
@ -174,7 +172,7 @@ impl UrlBuf {
|
|||
|
||||
impl UrlBuf {
|
||||
#[inline]
|
||||
pub fn as_url(&self) -> Url<'_> { Url::from(self) }
|
||||
pub fn as_url(&self) -> Url<'_> { Url { loc: self.loc.as_loc(), scheme: self.scheme.as_ref() } }
|
||||
|
||||
#[inline]
|
||||
pub fn base(&self) -> Option<Url<'_>> { self.as_url().base() }
|
||||
|
|
|
|||
|
|
@ -33,10 +33,6 @@ impl From<UrlBuf> for UrlCow<'_> {
|
|||
fn from(value: UrlBuf) -> Self { Self::Owned { loc: value.loc, scheme: value.scheme.into() } }
|
||||
}
|
||||
|
||||
impl<'a> From<&'a UrlCow<'a>> for Url<'a> {
|
||||
fn from(value: &'a UrlCow<'a>) -> Self { value.as_url() }
|
||||
}
|
||||
|
||||
impl From<UrlCow<'_>> for UrlBuf {
|
||||
fn from(value: UrlCow<'_>) -> Self { value.into_owned() }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use crate::url::{Url, UrlCow};
|
||||
use crate::url::{Url, UrlBuf, UrlCow};
|
||||
|
||||
pub trait AsUrl {
|
||||
fn as_url(&self) -> Url<'_>;
|
||||
|
|
@ -9,6 +9,21 @@ impl AsUrl for Url<'_> {
|
|||
fn as_url(&self) -> Url<'_> { *self }
|
||||
}
|
||||
|
||||
impl AsUrl for UrlBuf {
|
||||
#[inline]
|
||||
fn as_url(&self) -> Url<'_> { self.as_url() }
|
||||
}
|
||||
|
||||
impl AsUrl for &UrlBuf {
|
||||
#[inline]
|
||||
fn as_url(&self) -> Url<'_> { (**self).as_url() }
|
||||
}
|
||||
|
||||
impl AsUrl for &mut UrlBuf {
|
||||
#[inline]
|
||||
fn as_url(&self) -> Url<'_> { (**self).as_url() }
|
||||
}
|
||||
|
||||
impl AsUrl for UrlCow<'_> {
|
||||
#[inline]
|
||||
fn as_url(&self) -> Url<'_> { self.as_url() }
|
||||
|
|
@ -16,5 +31,13 @@ impl AsUrl for UrlCow<'_> {
|
|||
|
||||
impl AsUrl for &UrlCow<'_> {
|
||||
#[inline]
|
||||
fn as_url(&self) -> Url<'_> { (*self).as_url() }
|
||||
fn as_url(&self) -> Url<'_> { (**self).as_url() }
|
||||
}
|
||||
|
||||
impl<'a, T: AsUrl> From<&'a T> for Url<'a> {
|
||||
fn from(value: &'a T) -> Self { value.as_url() }
|
||||
}
|
||||
|
||||
impl<'a, T: AsUrl> From<&'a mut T> for Url<'a> {
|
||||
fn from(value: &'a mut T) -> Self { value.as_url() }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::{borrow::Cow, ffi::OsStr, fmt::{Debug, Formatter}, path::Path};
|
|||
|
||||
use hashbrown::Equivalent;
|
||||
|
||||
use crate::{loc::{Loc, LocBuf}, scheme::SchemeRef, url::{Components, Encode, Uri, UrlBuf, Urn}};
|
||||
use crate::{loc::{Loc, LocBuf}, scheme::SchemeRef, url::{AsUrl, Components, Encode, Uri, UrlBuf, Urn}};
|
||||
|
||||
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
|
||||
pub struct Url<'a> {
|
||||
|
|
@ -10,16 +10,6 @@ pub struct Url<'a> {
|
|||
pub scheme: SchemeRef<'a>,
|
||||
}
|
||||
|
||||
impl<'a> From<&'a UrlBuf> for Url<'a> {
|
||||
fn from(value: &'a UrlBuf) -> Self {
|
||||
Self { loc: value.loc.as_loc(), scheme: value.scheme.as_ref() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a mut UrlBuf> for Url<'a> {
|
||||
fn from(value: &'a mut UrlBuf) -> Self { Self::from(&*value) }
|
||||
}
|
||||
|
||||
// --- Eq
|
||||
impl PartialEq<UrlBuf> for Url<'_> {
|
||||
fn eq(&self, other: &UrlBuf) -> bool { *self == other.as_url() }
|
||||
|
|
@ -142,14 +132,14 @@ impl<'a> Url<'a> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn starts_with<'b>(self, base: impl Into<Url<'b>>) -> bool {
|
||||
let base: Url = base.into();
|
||||
pub fn starts_with(self, base: impl AsUrl) -> bool {
|
||||
let base = base.as_url();
|
||||
self.scheme.covariant(base.scheme) && self.loc.starts_with(base.loc)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn ends_with<'b>(self, child: impl Into<Url<'b>>) -> bool {
|
||||
let child: Url = child.into();
|
||||
pub fn ends_with(self, child: impl AsUrl) -> bool {
|
||||
let child = child.as_url();
|
||||
self.scheme.covariant(child.scheme) && self.loc.ends_with(child.loc)
|
||||
}
|
||||
|
||||
|
|
@ -160,8 +150,8 @@ impl<'a> Url<'a> {
|
|||
pub fn os_str(self) -> Cow<'a, OsStr> { self.components().os_str() }
|
||||
|
||||
#[inline]
|
||||
pub fn covariant(self, other: impl Into<Self>) -> bool {
|
||||
let other = other.into();
|
||||
pub fn covariant(self, other: impl AsUrl) -> bool {
|
||||
let other = other.as_url();
|
||||
self.scheme.covariant(other.scheme) && self.loc == other.loc
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,9 +22,7 @@ futures = { workspace = true }
|
|||
hashbrown = { workspace = true }
|
||||
parking_lot = { workspace = true }
|
||||
russh = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
toml = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
|
||||
[target."cfg(unix)".dependencies]
|
||||
|
|
|
|||
|
|
@ -1,30 +1,30 @@
|
|||
use std::io;
|
||||
|
||||
use yazi_fs::cha::{Cha, ChaKind};
|
||||
use yazi_shared::url::Url;
|
||||
use yazi_shared::url::AsUrl;
|
||||
|
||||
use crate::provider;
|
||||
|
||||
pub trait VfsCha: Sized {
|
||||
fn from_url<'a>(url: impl Into<Url<'a>>) -> impl Future<Output = io::Result<Self>>;
|
||||
fn from_url(url: impl AsUrl) -> impl Future<Output = io::Result<Self>>;
|
||||
|
||||
fn from_follow<'a, U>(url: U, cha: Self) -> impl Future<Output = Self>
|
||||
fn from_follow<U>(url: U, cha: Self) -> impl Future<Output = Self>
|
||||
where
|
||||
U: Into<Url<'a>>;
|
||||
U: AsUrl;
|
||||
}
|
||||
|
||||
impl VfsCha for Cha {
|
||||
#[inline]
|
||||
async fn from_url<'a>(url: impl Into<Url<'a>>) -> io::Result<Self> {
|
||||
let url = url.into();
|
||||
async fn from_url(url: impl AsUrl) -> io::Result<Self> {
|
||||
let url = url.as_url();
|
||||
Ok(Self::from_follow(url, provider::symlink_metadata(url).await?).await)
|
||||
}
|
||||
|
||||
async fn from_follow<'a, U>(url: U, mut cha: Self) -> Self
|
||||
async fn from_follow<U>(url: U, mut cha: Self) -> Self
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
U: AsUrl,
|
||||
{
|
||||
let url: Url = url.into();
|
||||
let url = url.as_url();
|
||||
let mut retain = cha.kind & (ChaKind::HIDDEN | ChaKind::SYSTEM);
|
||||
|
||||
if cha.is_link() {
|
||||
|
|
|
|||
|
|
@ -3,12 +3,12 @@ use std::{ffi::OsString, io};
|
|||
use tokio::{select, sync::{mpsc, oneshot}};
|
||||
use yazi_fs::cha::Cha;
|
||||
use yazi_macro::ok_or_not_found;
|
||||
use yazi_shared::url::{Url, UrlBuf};
|
||||
use yazi_shared::url::{AsUrl, UrlBuf};
|
||||
|
||||
use crate::provider;
|
||||
|
||||
#[inline]
|
||||
pub async fn maybe_exists<'a>(url: impl Into<Url<'a>>) -> bool {
|
||||
pub async fn maybe_exists(url: impl AsUrl) -> bool {
|
||||
match provider::symlink_metadata(url).await {
|
||||
Ok(_) => true,
|
||||
Err(e) => e.kind() != io::ErrorKind::NotFound,
|
||||
|
|
@ -16,7 +16,7 @@ pub async fn maybe_exists<'a>(url: impl Into<Url<'a>>) -> bool {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub async fn must_be_dir<'a>(url: impl Into<Url<'a>>) -> bool {
|
||||
pub async fn must_be_dir(url: impl AsUrl) -> bool {
|
||||
provider::metadata(url).await.is_ok_and(|m| m.is_dir())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
#![allow(clippy::if_same_then_else, clippy::unit_arg)]
|
||||
|
||||
yazi_macro::mod_pub!(provider);
|
||||
|
||||
yazi_macro::mod_flat!(cha file files fns op);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::{collections::VecDeque, io, time::{Duration, Instant}};
|
||||
|
||||
use yazi_fs::provider::{DirReader, FileHolder};
|
||||
use yazi_shared::{Either, url::{Url, UrlBuf}};
|
||||
use yazi_shared::{Either, url::{AsUrl, UrlBuf}};
|
||||
|
||||
use super::ReadDir;
|
||||
|
||||
|
|
@ -11,11 +11,11 @@ pub enum SizeCalculator {
|
|||
}
|
||||
|
||||
impl SizeCalculator {
|
||||
pub async fn new<'a, U>(url: U) -> io::Result<Self>
|
||||
pub async fn new<U>(url: U) -> io::Result<Self>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
U: AsUrl,
|
||||
{
|
||||
let url: Url = url.into();
|
||||
let url = url.as_url();
|
||||
let cha = super::symlink_metadata(url).await?;
|
||||
Ok(if cha.is_dir() {
|
||||
Self::Dir(VecDeque::from([Either::Left(url.to_owned())]))
|
||||
|
|
@ -24,9 +24,9 @@ impl SizeCalculator {
|
|||
})
|
||||
}
|
||||
|
||||
pub async fn total<'a, U>(url: U) -> io::Result<u64>
|
||||
pub async fn total<U>(url: U) -> io::Result<u64>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
U: AsUrl,
|
||||
{
|
||||
let mut it = Self::new(url).await?;
|
||||
let mut total = 0;
|
||||
|
|
|
|||
|
|
@ -2,23 +2,22 @@ use std::{io, path::{Path, PathBuf}};
|
|||
|
||||
use tokio::io::{BufReader, BufWriter};
|
||||
use yazi_fs::{cha::Cha, provider::{Provider, local::Local}};
|
||||
use yazi_shared::{scheme::SchemeRef, url::{Url, UrlBuf, UrlCow}};
|
||||
use yazi_shared::{scheme::SchemeRef, url::{AsUrl, UrlBuf, UrlCow}};
|
||||
|
||||
use super::{Providers, ReadDir, RwFile};
|
||||
|
||||
pub async fn absolute<'a, U>(url: U) -> io::Result<UrlCow<'a>>
|
||||
pub async fn absolute<'a, U>(url: &'a U) -> io::Result<UrlCow<'a>>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
U: AsUrl,
|
||||
{
|
||||
let url: Url = url.into();
|
||||
Providers::new(url).await?.absolute(url).await
|
||||
Providers::new(url.as_url()).await?.absolute(url).await
|
||||
}
|
||||
|
||||
pub async fn calculate<'a, U>(url: U) -> io::Result<u64>
|
||||
pub async fn calculate<U>(url: U) -> io::Result<u64>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
U: AsUrl,
|
||||
{
|
||||
let url: Url = url.into();
|
||||
let url = url.as_url();
|
||||
if let Some(path) = url.as_path() {
|
||||
yazi_fs::provider::local::SizeCalculator::total(path).await
|
||||
} else {
|
||||
|
|
@ -26,11 +25,11 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn canonicalize<'a, U>(url: U) -> io::Result<UrlBuf>
|
||||
pub async fn canonicalize<U>(url: U) -> io::Result<UrlBuf>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
U: AsUrl,
|
||||
{
|
||||
let url: Url = url.into();
|
||||
let url = url.as_url();
|
||||
let canon = Providers::new(url).await?.canonicalize(url.loc).await?;
|
||||
|
||||
Ok(match url.scheme {
|
||||
|
|
@ -42,11 +41,11 @@ where
|
|||
})
|
||||
}
|
||||
|
||||
pub async fn casefold<'a, U>(url: U) -> io::Result<UrlBuf>
|
||||
pub async fn casefold<U>(url: U) -> io::Result<UrlBuf>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
U: AsUrl,
|
||||
{
|
||||
let url: Url = url.into();
|
||||
let url = url.as_url();
|
||||
let fold = Providers::new(url).await?.casefold(url.loc).await?;
|
||||
|
||||
Ok(match url.scheme {
|
||||
|
|
@ -58,12 +57,12 @@ where
|
|||
})
|
||||
}
|
||||
|
||||
pub async fn copy<'a, U, V>(from: U, to: V, cha: Cha) -> io::Result<u64>
|
||||
pub async fn copy<U, V>(from: U, to: V, cha: Cha) -> io::Result<u64>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
V: Into<Url<'a>>,
|
||||
U: AsUrl,
|
||||
V: AsUrl,
|
||||
{
|
||||
let (from, to): (Url, Url) = (from.into(), to.into());
|
||||
let (from, to) = (from.as_url(), to.as_url());
|
||||
|
||||
match (from.as_path(), to.as_path()) {
|
||||
(Some(from), Some(to)) => Local.copy(from, to, cha).await,
|
||||
|
|
@ -85,36 +84,36 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn create<'a, U>(url: U) -> io::Result<RwFile>
|
||||
pub async fn create<U>(url: U) -> io::Result<RwFile>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
U: AsUrl,
|
||||
{
|
||||
let url: Url = url.into();
|
||||
let url = url.as_url();
|
||||
Providers::new(url).await?.create(url.loc).await
|
||||
}
|
||||
|
||||
pub async fn create_dir<'a, U>(url: U) -> io::Result<()>
|
||||
pub async fn create_dir<U>(url: U) -> io::Result<()>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
U: AsUrl,
|
||||
{
|
||||
let url: Url = url.into();
|
||||
let url = url.as_url();
|
||||
Providers::new(url).await?.create_dir(url.loc).await
|
||||
}
|
||||
|
||||
pub async fn create_dir_all<'a, U>(url: U) -> io::Result<()>
|
||||
pub async fn create_dir_all<U>(url: U) -> io::Result<()>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
U: AsUrl,
|
||||
{
|
||||
let url: Url = url.into();
|
||||
let url = url.as_url();
|
||||
Providers::new(url).await?.create_dir_all(url.loc).await
|
||||
}
|
||||
|
||||
pub async fn hard_link<'a, U, V>(original: U, link: V) -> io::Result<()>
|
||||
pub async fn hard_link<U, V>(original: U, link: V) -> io::Result<()>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
V: Into<Url<'a>>,
|
||||
U: AsUrl,
|
||||
V: AsUrl,
|
||||
{
|
||||
let (original, link): (Url, Url) = (original.into(), link.into());
|
||||
let (original, link) = (original.as_url(), link.as_url());
|
||||
if original.scheme.covariant(link.scheme) {
|
||||
Providers::new(original).await?.hard_link(original.loc, link.loc).await
|
||||
} else {
|
||||
|
|
@ -122,88 +121,88 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn identical<'a, U, V>(a: U, b: V) -> io::Result<bool>
|
||||
pub async fn identical<U, V>(a: U, b: V) -> io::Result<bool>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
V: Into<Url<'a>>,
|
||||
U: AsUrl,
|
||||
V: AsUrl,
|
||||
{
|
||||
if let (Some(a), Some(b)) = (a.into().as_path(), b.into().as_path()) {
|
||||
if let (Some(a), Some(b)) = (a.as_url().as_path(), b.as_url().as_path()) {
|
||||
yazi_fs::provider::local::identical(a, b).await
|
||||
} else {
|
||||
Err(io::Error::new(io::ErrorKind::Unsupported, "Unsupported filesystem"))
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn metadata<'a, U>(url: U) -> io::Result<Cha>
|
||||
pub async fn metadata<U>(url: U) -> io::Result<Cha>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
U: AsUrl,
|
||||
{
|
||||
let url: Url = url.into();
|
||||
let url = url.as_url();
|
||||
Providers::new(url).await?.metadata(url.loc).await
|
||||
}
|
||||
|
||||
pub async fn must_identical<'a, U, V>(a: U, b: V) -> bool
|
||||
pub async fn must_identical<U, V>(a: U, b: V) -> bool
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
V: Into<Url<'a>>,
|
||||
U: AsUrl,
|
||||
V: AsUrl,
|
||||
{
|
||||
identical(a, b).await.unwrap_or(false)
|
||||
}
|
||||
|
||||
pub async fn read_dir<'a, U>(url: U) -> io::Result<ReadDir>
|
||||
pub async fn read_dir<U>(url: U) -> io::Result<ReadDir>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
U: AsUrl,
|
||||
{
|
||||
let url: Url = url.into();
|
||||
let url = url.as_url();
|
||||
Providers::new(url).await?.read_dir(url.loc).await
|
||||
}
|
||||
|
||||
pub async fn read_link<'a, U>(url: U) -> io::Result<PathBuf>
|
||||
pub async fn read_link<U>(url: U) -> io::Result<PathBuf>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
U: AsUrl,
|
||||
{
|
||||
let url: Url = url.into();
|
||||
let url = url.as_url();
|
||||
Providers::new(url).await?.read_link(url.loc).await
|
||||
}
|
||||
|
||||
pub async fn remove_dir<'a, U>(url: U) -> io::Result<()>
|
||||
pub async fn remove_dir<U>(url: U) -> io::Result<()>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
U: AsUrl,
|
||||
{
|
||||
let url: Url = url.into();
|
||||
let url = url.as_url();
|
||||
Providers::new(url).await?.remove_dir(url.loc).await
|
||||
}
|
||||
|
||||
pub async fn remove_dir_all<'a, U>(url: U) -> io::Result<()>
|
||||
pub async fn remove_dir_all<U>(url: U) -> io::Result<()>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
U: AsUrl,
|
||||
{
|
||||
let url: Url = url.into();
|
||||
let url = url.as_url();
|
||||
Providers::new(url).await?.remove_dir_all(url.loc).await
|
||||
}
|
||||
|
||||
pub async fn remove_dir_clean<'a, U>(url: U) -> io::Result<()>
|
||||
pub async fn remove_dir_clean<U>(url: U) -> io::Result<()>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
U: AsUrl,
|
||||
{
|
||||
let url: Url = url.into();
|
||||
let url = url.as_url();
|
||||
Ok(Providers::new(url).await?.remove_dir_clean(url.loc).await)
|
||||
}
|
||||
|
||||
pub async fn remove_file<'a, U>(url: U) -> io::Result<()>
|
||||
pub async fn remove_file<U>(url: U) -> io::Result<()>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
U: AsUrl,
|
||||
{
|
||||
let url: Url = url.into();
|
||||
let url = url.as_url();
|
||||
Providers::new(url).await?.remove_file(url.loc).await
|
||||
}
|
||||
|
||||
pub async fn rename<'a, U, V>(from: U, to: V) -> io::Result<()>
|
||||
pub async fn rename<U, V>(from: U, to: V) -> io::Result<()>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
V: Into<Url<'a>>,
|
||||
U: AsUrl,
|
||||
V: AsUrl,
|
||||
{
|
||||
let (from, to): (Url, Url) = (from.into(), to.into());
|
||||
let (from, to) = (from.as_url(), to.as_url());
|
||||
if from.scheme.covariant(to.scheme) {
|
||||
Providers::new(from).await?.rename(from.loc, to.loc).await
|
||||
} else {
|
||||
|
|
@ -211,52 +210,52 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn symlink<'a, U, F>(original: &Path, link: U, is_dir: F) -> io::Result<()>
|
||||
pub async fn symlink<U, F>(original: &Path, link: U, is_dir: F) -> io::Result<()>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
U: AsUrl,
|
||||
F: AsyncFnOnce() -> io::Result<bool>,
|
||||
{
|
||||
let link: Url = link.into();
|
||||
let link = link.as_url();
|
||||
Providers::new(link).await?.symlink(original, link.loc, is_dir).await
|
||||
}
|
||||
|
||||
pub async fn symlink_dir<'a, U>(original: &Path, link: U) -> io::Result<()>
|
||||
pub async fn symlink_dir<U>(original: &Path, link: U) -> io::Result<()>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
U: AsUrl,
|
||||
{
|
||||
let link: Url = link.into();
|
||||
let link = link.as_url();
|
||||
Providers::new(link).await?.symlink_dir(original, link.loc).await
|
||||
}
|
||||
|
||||
pub async fn symlink_file<'a, U>(original: &Path, link: U) -> io::Result<()>
|
||||
pub async fn symlink_file<U>(original: &Path, link: U) -> io::Result<()>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
U: AsUrl,
|
||||
{
|
||||
let link: Url = link.into();
|
||||
let link = link.as_url();
|
||||
Providers::new(link).await?.symlink_file(original, link.loc).await
|
||||
}
|
||||
|
||||
pub async fn symlink_metadata<'a, U>(url: U) -> io::Result<Cha>
|
||||
pub async fn symlink_metadata<U>(url: U) -> io::Result<Cha>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
U: AsUrl,
|
||||
{
|
||||
let url: Url = url.into();
|
||||
let url = url.as_url();
|
||||
Providers::new(url).await?.symlink_metadata(url.loc).await
|
||||
}
|
||||
|
||||
pub async fn trash<'a, U>(url: U) -> io::Result<()>
|
||||
pub async fn trash<U>(url: U) -> io::Result<()>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
U: AsUrl,
|
||||
{
|
||||
let url: Url = url.into();
|
||||
let url = url.as_url();
|
||||
Providers::new(url).await?.trash(url.loc).await
|
||||
}
|
||||
|
||||
pub async fn write<'a, U, C>(url: U, contents: C) -> io::Result<()>
|
||||
pub async fn write<U, C>(url: U, contents: C) -> io::Result<()>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
U: AsUrl,
|
||||
C: AsRef<[u8]>,
|
||||
{
|
||||
let url: Url = url.into();
|
||||
let url = url.as_url();
|
||||
Providers::new(url).await?.write(url.loc, contents).await
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use std::{io, path::{Path, PathBuf}, sync::Arc};
|
|||
|
||||
use yazi_config::vfs::{ProviderSftp, Vfs};
|
||||
use yazi_fs::{cha::Cha, provider::{Provider, local::Local}};
|
||||
use yazi_shared::{scheme::SchemeRef, url::{Url, UrlCow}};
|
||||
use yazi_shared::{scheme::SchemeRef, url::{AsUrl, Url, UrlCow}};
|
||||
|
||||
pub(super) struct Providers<'a>(Inner<'a>);
|
||||
|
||||
|
|
@ -32,9 +32,9 @@ impl Provider for Providers<'_> {
|
|||
type Gate = super::Gate;
|
||||
type ReadDir = super::ReadDir;
|
||||
|
||||
async fn absolute<'a, U>(&self, url: U) -> io::Result<UrlCow<'a>>
|
||||
async fn absolute<'a, U>(&self, url: &'a U) -> io::Result<UrlCow<'a>>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
U: AsUrl,
|
||||
{
|
||||
match self.0 {
|
||||
Inner::Regular | Inner::Search(_) => Local.absolute(url).await,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use tokio::io::{BufReader, BufWriter};
|
|||
use yazi_config::vfs::ProviderSftp;
|
||||
use yazi_fs::provider::{DirReader, FileBuilder, FileHolder, Provider, local::Local};
|
||||
use yazi_sftp::fs::{Attrs, Flags};
|
||||
use yazi_shared::{scheme::SchemeRef, url::{Url, UrlBuf, UrlCow}};
|
||||
use yazi_shared::{scheme::SchemeRef, url::{AsUrl, UrlBuf, UrlCow}};
|
||||
|
||||
use super::Cha;
|
||||
|
||||
|
|
@ -24,11 +24,11 @@ impl Provider for Sftp {
|
|||
type Gate = super::Gate;
|
||||
type ReadDir = super::ReadDir;
|
||||
|
||||
async fn absolute<'a, U>(&self, url: U) -> io::Result<UrlCow<'a>>
|
||||
async fn absolute<'a, U>(&self, url: &'a U) -> io::Result<UrlCow<'a>>
|
||||
where
|
||||
U: Into<Url<'a>>,
|
||||
U: AsUrl,
|
||||
{
|
||||
let url: Url = url.into();
|
||||
let url = url.as_url();
|
||||
Ok(if url.is_absolute() {
|
||||
url.into()
|
||||
} else if let SchemeRef::Sftp(_) = url.scheme {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use anyhow::Result;
|
|||
use hashbrown::HashSet;
|
||||
use tokio::sync::mpsc;
|
||||
use tracing::error;
|
||||
use yazi_shared::url::{Url, UrlBuf};
|
||||
use yazi_shared::url::{AsUrl, Url, UrlBuf};
|
||||
|
||||
use crate::{LINKED, WATCHED, backend};
|
||||
|
||||
|
|
@ -64,11 +64,11 @@ impl Backend {
|
|||
todo.into_iter().for_each(|u| _ = out_tx.send(u));
|
||||
}
|
||||
|
||||
fn watch<'a>(&mut self, url: impl Into<Url<'a>>) -> Result<()> {
|
||||
if let Some(path) = url.into().as_path() { self.local.watch(path) } else { Ok(()) }
|
||||
fn watch(&mut self, url: impl AsUrl) -> Result<()> {
|
||||
if let Some(path) = url.as_url().as_path() { self.local.watch(path) } else { Ok(()) }
|
||||
}
|
||||
|
||||
fn unwatch<'a>(&mut self, url: impl Into<Url<'a>>) -> Result<()> {
|
||||
if let Some(path) = url.into().as_path() { self.local.unwatch(path) } else { Ok(()) }
|
||||
fn unwatch(&mut self, url: impl AsUrl) -> Result<()> {
|
||||
if let Some(path) = url.as_url().as_path() { self.local.unwatch(path) } else { Ok(()) }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,10 +20,10 @@ impl DerefMut for Linked {
|
|||
}
|
||||
|
||||
impl Linked {
|
||||
pub fn from_dir<'a, 'b, T>(&'a self, url: T) -> Box<dyn Iterator<Item = &'a Path> + 'b>
|
||||
pub fn from_dir<'a, 'b, U>(&'a self, url: U) -> Box<dyn Iterator<Item = &'a Path> + 'b>
|
||||
where
|
||||
'a: 'b,
|
||||
T: Into<Url<'b>>,
|
||||
U: Into<Url<'b>>,
|
||||
{
|
||||
let url: Url = url.into();
|
||||
let Some(path) = url.as_path() else {
|
||||
|
|
|
|||
|
|
@ -1,16 +1,14 @@
|
|||
use std::path::Path;
|
||||
|
||||
use hashbrown::HashSet;
|
||||
use yazi_shared::url::{Url, UrlBuf};
|
||||
use yazi_shared::url::{AsUrl, UrlBuf};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Watched(HashSet<UrlBuf>);
|
||||
|
||||
impl Watched {
|
||||
#[inline]
|
||||
pub(crate) fn contains<'a>(&self, url: impl Into<Url<'a>>) -> bool {
|
||||
self.0.contains(&url.into())
|
||||
}
|
||||
pub(crate) fn contains(&self, url: impl AsUrl) -> bool { self.0.contains(&url.as_url()) }
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn diff(&self, new: &HashSet<UrlBuf>) -> (Vec<UrlBuf>, Vec<UrlBuf>) {
|
||||
|
|
@ -26,5 +24,5 @@ impl Watched {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn remove<'a>(&mut self, url: impl Into<Url<'a>>) { self.0.remove(&url.into()); }
|
||||
pub(crate) fn remove(&mut self, url: impl AsUrl) { self.0.remove(&url.as_url()); }
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue