feat!: folder mime-type support (#3222)

This commit is contained in:
三咲雅 misaki masa 2025-10-01 20:03:41 +08:00 committed by GitHub
parent 879ed49996
commit 4d39194cd8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
216 changed files with 1245 additions and 981 deletions

View file

@ -87,6 +87,14 @@ See https://yazi-rs.github.io/docs/image-preview for details.
[ueberzug]: https://github.com/jstkdng/ueberzugpp
[chafa]: https://hpjansson.org/chafa/
## Special Thanks
<img alt="RustRover logo" align="right" width="200" src="https://resources.jetbrains.com/storage/products/company/brand/logos/RustRover.svg">
Thanks to RustRover team for providing open-source licenses to support the maintenance of Yazi.
Active code contributors can contact @sxyazi to get a license (if any are still available).
## License
Yazi is MIT-licensed. For more information check the [LICENSE](LICENSE) file.

View file

@ -1,6 +1,6 @@
use anyhow::Result;
use yazi_dds::spark::SparkKind;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::Ctx;

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::{render, succ};
use yazi_parser::ArrowOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use yazi_widgets::Scrollable;
use crate::{Actor, Ctx};

View file

@ -3,7 +3,7 @@ use std::mem;
use anyhow::Result;
use yazi_macro::{act, render, succ};
use yazi_parser::{cmp::CloseOpt, input::CompleteOpt};
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -3,7 +3,7 @@ use std::{ffi::OsStr, mem, ops::ControlFlow};
use anyhow::Result;
use yazi_macro::{render, succ};
use yazi_parser::cmp::{CmpItem, ShowOpt};
use yazi_shared::{event::Data, osstr_contains, osstr_starts_with};
use yazi_shared::{data::Data, osstr_contains, osstr_starts_with};
use crate::{Actor, Ctx};

View file

@ -5,7 +5,7 @@ use yazi_fs::{CWD, path::expand_url, provider::{DirReader, FileHolder}};
use yazi_macro::{act, render, succ};
use yazi_parser::cmp::{CmpItem, ShowOpt, TriggerOpt};
use yazi_proxy::CmpProxy;
use yazi_shared::{OsStrSplit, event::Data, natsort, url::{UrlBuf, UrlCow, UrnBuf}};
use yazi_shared::{OsStrSplit, data::Data, natsort, url::{UrlBuf, UrlCow, UrnBuf}};
use yazi_vfs::provider;
use crate::{Actor, Ctx};

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::{render, succ};
use yazi_parser::ArrowOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::{render, succ};
use yazi_parser::confirm::CloseOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::{act, render, succ};
use yazi_parser::confirm::ShowOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -3,7 +3,7 @@ use std::ops::{Deref, DerefMut};
use anyhow::{Result, anyhow};
use yazi_core::{Core, mgr::Tabs, tab::{Folder, Tab}, tasks::Tasks};
use yazi_fs::File;
use yazi_shared::{Source, event::Cmd, url::UrlBuf};
use yazi_shared::{Id, Source, event::Cmd, url::UrlBuf};
pub struct Ctx<'a> {
pub core: &'a mut Core,
@ -25,7 +25,7 @@ impl DerefMut for Ctx<'_> {
impl<'a> Ctx<'a> {
#[inline]
pub fn new(core: &'a mut Core, cmd: &Cmd) -> Result<Self> {
let tab = if let Some(id) = cmd.id("tab") {
let tab = if let Ok(id) = cmd.get::<Id>("tab") {
core
.mgr
.tabs

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::{render, succ};
use yazi_parser::ArrowOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use yazi_widgets::Scrollable;
use crate::{Actor, Ctx};

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::{act, render, succ};
use yazi_parser::VoidOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::{render, succ};
use yazi_parser::VoidOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::{render, succ};
use yazi_parser::help::ToggleOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::{act, render, succ};
use yazi_parser::input::CloseOpt;
use yazi_shared::{errors::InputError, event::Data};
use yazi_shared::{data::Data, errors::InputError};
use crate::{Actor, Ctx};

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::{act, render, succ};
use yazi_parser::VoidOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use yazi_widgets::input::InputOp;
use crate::{Actor, Ctx};

View file

@ -4,7 +4,7 @@ use anyhow::Result;
use yazi_config::YAZI;
use yazi_macro::{act, render, succ};
use yazi_parser::input::ShowOpt;
use yazi_shared::{errors::InputError, event::Data};
use yazi_shared::{data::Data, errors::InputError};
use yazi_widgets::input::InputCallback;
use crate::{Actor, Ctx};

View file

@ -80,7 +80,7 @@ impl UserData for File {
});
methods.add_method("mime", |lua, me, ()| {
lua.named_registry_value::<AnyUserData>("cx")?.borrow_scoped(|core: &yazi_core::Core| {
core.mgr.mimetype.by_url(&me.url).map(|s| lua.create_string(s)).transpose()
core.mgr.mimetype.get(&me.url).map(|s| lua.create_string(s)).transpose()
})?
});
methods.add_method("prefix", |lua, me, ()| {
@ -97,7 +97,7 @@ impl UserData for File {
});
methods.add_method("style", |lua, me, ()| {
lua.named_registry_value::<AnyUserData>("cx")?.borrow_scoped(|core: &yazi_core::Core| {
let mime = core.mgr.mimetype.by_file(me).unwrap_or_default();
let mime = core.mgr.mimetype.get(&me.url).unwrap_or_default();
THEME.filetype.iter().find(|&x| x.matches(me, mime)).map(|x| Style::from(x.style))
})
});

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::{act, render, succ};
use yazi_parser::ArrowOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::{act, succ};
use yazi_parser::{VoidOpt, mgr::CdSource};
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -1,4 +1,4 @@
use std::{borrow::Cow, ffi::{OsStr, OsString}, hash::Hash, io::{Read, Write}, ops::Deref, path::Path};
use std::{borrow::Cow, ffi::{OsStr, OsString}, hash::Hash, io::{Read, Write}, ops::Deref};
use anyhow::{Result, anyhow};
use crossterm::{execute, style::Print};
@ -11,7 +11,7 @@ use yazi_fs::{File, FilesOp, max_common_root, path::skip_url, provider::{FileBui
use yazi_macro::{err, succ};
use yazi_parser::VoidOpt;
use yazi_proxy::{AppProxy, HIDER, TasksProxy};
use yazi_shared::{OsStrJoin, event::Data, terminal_clear, url::{Component, UrlBuf}};
use yazi_shared::{OsStrJoin, data::Data, terminal_clear, url::{Component, Url, UrlBuf}};
use yazi_term::tty::TTY;
use yazi_vfs::{VfsFile, maybe_exists, provider};
use yazi_watcher::WATCHER;
@ -52,8 +52,8 @@ impl Actor for BulkRename {
defer! { tokio::spawn(Local.remove_file(tmp.clone())); }
TasksProxy::process_exec(Cow::Borrowed(opener), cwd, vec![
OsString::new(),
tmp.to_owned().into(),
OsStr::new("").into(),
tmp.as_os_str().to_owned().into(),
])
.await;
@ -147,7 +147,7 @@ impl BulkRename {
}
fn opener() -> Option<&'static OpenerRule> {
YAZI.opener.block(YAZI.open.all(UrlBuf::from(Path::new("bulk-rename.txt")), "text/plain"))
YAZI.opener.block(YAZI.open.all(Url::regular("bulk-rename.txt"), "text/plain"))
}
async fn output_failed(failed: Vec<(Tuple, Tuple, anyhow::Error)>) -> Result<()> {

View file

@ -9,7 +9,7 @@ use yazi_fs::{File, FilesOp, path::expand_url};
use yazi_macro::{act, err, render, succ};
use yazi_parser::mgr::CdOpt;
use yazi_proxy::{CmpProxy, InputProxy, MgrProxy};
use yazi_shared::{Debounce, errors::InputError, event::Data, url::UrlBuf};
use yazi_shared::{Debounce, data::Data, errors::InputError, url::UrlBuf};
use yazi_vfs::VfsFile;
use crate::{Actor, Ctx};

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::act;
use yazi_parser::mgr::CloseOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -3,7 +3,7 @@ use std::ffi::OsString;
use anyhow::{Result, bail};
use yazi_macro::{act, succ};
use yazi_parser::mgr::CopyOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use yazi_widgets::CLIPBOARD;
use crate::{Actor, Ctx};

View file

@ -1,10 +1,10 @@
use anyhow::{Result, bail};
use yazi_config::popup::{ConfirmCfg, InputCfg};
use yazi_fs::{File, FilesOp, ok_or_not_found};
use yazi_macro::succ;
use yazi_fs::{File, FilesOp};
use yazi_macro::{ok_or_not_found, succ};
use yazi_parser::mgr::CreateOpt;
use yazi_proxy::{ConfirmProxy, InputProxy, MgrProxy};
use yazi_shared::{event::Data, url::UrlBuf};
use yazi_shared::{data::Data, url::UrlBuf};
use yazi_vfs::{VfsFile, maybe_exists, provider};
use yazi_watcher::WATCHER;
@ -50,12 +50,12 @@ impl Create {
} else if let Ok(real) = provider::casefold(&new).await
&& let Some((parent, urn)) = real.pair()
{
ok_or_not_found(provider::remove_file(&new).await)?;
ok_or_not_found!(provider::remove_file(&new).await);
FilesOp::Deleting(parent.into(), [urn.into()].into()).emit();
provider::create(&new).await?;
} else if let Some(parent) = new.parent() {
provider::create_dir_all(parent).await.ok();
ok_or_not_found(provider::remove_file(&new).await)?;
ok_or_not_found!(provider::remove_file(&new).await);
provider::create(&new).await?;
} else {
bail!("Cannot create file at root");

View file

@ -0,0 +1,58 @@
use std::{mem, time::{Duration, Instant}};
use anyhow::Result;
use futures::{StreamExt, stream::FuturesUnordered};
use tokio::sync::oneshot;
use yazi_fs::File;
use yazi_macro::{act, succ};
use yazi_parser::mgr::DownloadOpt;
use yazi_shared::data::Data;
use yazi_vfs::VfsFile;
use crate::{Actor, Ctx};
pub struct Download;
impl Actor for Download {
type Options = DownloadOpt;
const NAME: &str = "download";
fn act(cx: &mut Ctx, opt: Self::Options) -> Result<Data> {
act!(mgr:escape_visual, cx)?;
let mut wg1 = FuturesUnordered::new();
for url in opt.urls {
let (tx, rx) = oneshot::channel();
cx.tasks.scheduler.file_download(url.to_owned(), Some(tx));
wg1.push(async move { (rx.await == Ok(true), url) });
}
let scheduler = cx.tasks.scheduler.clone();
tokio::spawn(async move {
let mut wg2 = vec![];
let mut files = Vec::with_capacity(wg1.len());
let mut instant = Instant::now();
while let Some((success, url)) = wg1.next().await {
if !success {
continue;
}
let Ok(f) = File::new(url).await else { continue };
files.push(f);
if instant.elapsed() >= Duration::from_secs(1) {
wg2.push(scheduler.fetch_mimetype(mem::take(&mut files)));
instant = Instant::now();
}
}
if !files.is_empty() {
wg2.push(scheduler.fetch_mimetype(files));
}
futures::future::join_all(wg2).await;
});
succ!();
}
}

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::{act, succ};
use yazi_parser::{VoidOpt, mgr::CdSource};
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -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::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -7,7 +7,7 @@ use yazi_config::popup::InputCfg;
use yazi_macro::succ;
use yazi_parser::mgr::FilterOpt;
use yazi_proxy::{InputProxy, MgrProxy};
use yazi_shared::{Debounce, errors::InputError, event::Data};
use yazi_shared::{Debounce, data::Data, errors::InputError};
use crate::{Actor, Ctx};

View file

@ -2,7 +2,7 @@ use anyhow::Result;
use yazi_fs::Filter;
use yazi_macro::{act, render, succ};
use yazi_parser::mgr::FilterOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -7,7 +7,7 @@ use yazi_config::popup::InputCfg;
use yazi_macro::succ;
use yazi_parser::mgr::{FindDoOpt, FindOpt};
use yazi_proxy::{InputProxy, MgrProxy};
use yazi_shared::{Debounce, errors::InputError, event::Data};
use yazi_shared::{Debounce, data::Data, errors::InputError};
use crate::{Actor, Ctx};

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::{act, render, succ};
use yazi_parser::mgr::FindArrowOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -2,7 +2,7 @@ use anyhow::Result;
use yazi_core::tab::Finder;
use yazi_macro::{act, render, succ};
use yazi_parser::mgr::FindDoOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -2,7 +2,7 @@ use anyhow::Result;
use yazi_fs::path::clean_url;
use yazi_macro::{act, succ};
use yazi_parser::VoidOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::{act, succ};
use yazi_parser::{VoidOpt, mgr::CdSource};
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::succ;
use yazi_parser::mgr::HardlinkOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -3,7 +3,7 @@ use yazi_core::tab::Folder;
use yazi_fs::FolderStage;
use yazi_macro::{act, render, render_and, succ};
use yazi_parser::mgr::HiddenOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -2,7 +2,7 @@ use anyhow::Result;
use yazi_dds::Pubsub;
use yazi_macro::{err, render, succ, tab};
use yazi_parser::mgr::HoverOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::{act, succ};
use yazi_parser::{VoidOpt, mgr::CdSource};
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::{render, succ};
use yazi_parser::mgr::LinemodeOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::succ;
use yazi_parser::mgr::LinkOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -6,6 +6,7 @@ yazi_macro::mod_flat!(
close
copy
create
download
enter
escape
filter
@ -22,6 +23,7 @@ yazi_macro::mod_flat!(
linemode
link
open
open_do
paste
peek
quit

View file

@ -1,14 +1,10 @@
use std::{borrow::Cow, iter};
use anyhow::Result;
use tokio::sync::oneshot;
use yazi_config::{YAZI, popup::PickCfg};
use yazi_core::tab::Folder;
use yazi_boot::ARGS;
use yazi_fs::File;
use yazi_macro::{act, succ};
use yazi_parser::mgr::{OpenDoOpt, OpenOpt};
use yazi_proxy::{MgrProxy, PickProxy, TasksProxy};
use yazi_shared::{MIME_DIR, event::Data, url::UrlBuf};
use yazi_proxy::MgrProxy;
use yazi_shared::{data::Data, url::UrlCow};
use yazi_vfs::VfsFile;
use crate::{Actor, Ctx, mgr::Quit};
@ -20,118 +16,59 @@ impl Actor for Open {
const NAME: &str = "open";
fn act(cx: &mut Ctx, opt: Self::Options) -> Result<Data> {
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()) else { succ!() };
let Some(hovered) = cx.hovered().map(|h| h.url_owned()).map(UrlCow::from) else { succ!() };
let mut selected =
if opt.hovered { Box::new(iter::once(&hovered)) } else { cx.tab().selected_or_hovered() };
if Quit::quit_with_selected(opt, &mut selected) {
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])
} else {
Quit::with_selected(cx.tab().selected_or_hovered())
});
}
let mut todo = vec![];
let targets: Vec<_> = selected
.cloned()
if opt.targets.is_empty() {
opt.targets = if opt.hovered {
vec![hovered.clone()]
} else {
cx.tab().selected_or_hovered().cloned().map(Into::into).collect()
};
}
let todo: Vec<_> = opt
.targets
.iter()
.enumerate()
.map(|(i, u)| {
if cx.mgr.mimetype.contains(&u) {
(u, "")
} else if Self::guess_folder(cx, &u) {
(u, MIME_DIR)
} else {
todo.push(i);
(u, "")
}
})
.filter(|&(_, u)| !cx.mgr.mimetype.contains(u))
.map(|(i, _)| i)
.collect();
let cwd = cx.cwd().clone();
if todo.is_empty() {
return act!(mgr:open_do, cx, OpenDoOpt { cwd, hovered, targets, interactive: opt.interactive });
return act!(mgr:open_do, cx, OpenDoOpt { cwd, hovered, targets: opt.targets, interactive: opt.interactive });
}
let scheduler = cx.tasks.scheduler.clone();
tokio::spawn(async move {
let mut files = Vec::with_capacity(todo.len());
for i in todo {
if let Ok(f) = File::new(&targets[i].0).await {
if let Ok(f) = File::new(&opt.targets[i]).await {
files.push(f);
}
}
let mut wg = vec![];
for (fetcher, files) in YAZI.plugin.mime_fetchers(files) {
let (tx, rx) = oneshot::channel();
scheduler.fetch_paged(fetcher, files, Some(tx));
wg.push(rx);
}
for rx in wg {
if !rx.await.is_ok_and(|canceled| !canceled) {
return;
}
}
MgrProxy::open_do(OpenDoOpt { cwd, hovered, targets, interactive: opt.interactive });
});
succ!();
}
}
// --- Do
pub struct OpenDo;
impl Actor for OpenDo {
type Options = OpenDoOpt;
const NAME: &str = "open_do";
fn act(cx: &mut Ctx, opt: Self::Options) -> Result<Data> {
let mut targets = opt.targets;
targets.iter_mut().filter(|(_, m)| m.is_empty()).for_each(|(u, m)| {
*m = cx.mgr.mimetype.by_url(u).unwrap_or_default();
});
targets.retain(|(_, m)| !m.is_empty());
if targets.is_empty() {
succ!();
} else if !opt.interactive {
succ!(cx.tasks.process_from_files(opt.cwd, opt.hovered, targets));
}
let openers: Vec<_> = YAZI.opener.all(YAZI.open.common(&targets).into_iter());
if openers.is_empty() {
succ!();
}
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();
tokio::spawn(async move {
if let Ok(choice) = pick.await {
TasksProxy::open_with(Cow::Borrowed(openers[choice]), opt.cwd, urls);
if scheduler.fetch_mimetype(files).await {
MgrProxy::open_do(OpenDoOpt {
cwd,
hovered,
targets: opt.targets,
interactive: opt.interactive,
});
}
});
succ!();
}
}
impl Open {
fn guess_folder(cx: &Ctx, url: &UrlBuf) -> bool {
let Some(p) = url.parent() else {
return true;
};
let find = |folder: Option<&Folder>| {
folder.is_some_and(|folder| {
p == folder.url && folder.files.iter().any(|f| f.is_dir() && f.urn() == url.urn())
})
};
find(Some(cx.current()))
|| find(cx.parent())
|| find(cx.hovered_folder())
|| find(cx.tab().history.get(&p))
}
}

View file

@ -0,0 +1,50 @@
use std::borrow::Cow;
use anyhow::Result;
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 crate::{Actor, Ctx};
pub struct OpenDo;
impl Actor for OpenDo {
type Options = OpenDoOpt;
const NAME: &str = "open_do";
fn act(cx: &mut Ctx, opt: Self::Options) -> Result<Data> {
let targets: Vec<_> = opt
.targets
.into_iter()
.map(|u| {
let m = cx.mgr.mimetype.get(&u).unwrap_or_default();
(u, m)
})
.filter(|(_, m)| !m.is_empty())
.collect();
if targets.is_empty() {
succ!();
} else if !opt.interactive {
succ!(cx.tasks.process_from_files(opt.cwd, opt.hovered, targets));
}
let openers: Vec<_> = YAZI.opener.all(YAZI.open.common(&targets).into_iter());
if openers.is_empty() {
succ!();
}
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();
tokio::spawn(async move {
if let Ok(choice) = pick.await {
TasksProxy::open_with(Cow::Borrowed(openers[choice]), opt.cwd, urls);
}
});
succ!();
}
}

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::{act, succ};
use yazi_parser::mgr::PasteOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -2,7 +2,7 @@ use anyhow::Result;
use yazi_macro::succ;
use yazi_parser::mgr::PeekOpt;
use yazi_proxy::HIDER;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};
@ -21,7 +21,7 @@ impl Actor for Peek {
succ!(cx.tab_mut().preview.reset_image());
}
let mime = cx.mgr.mimetype.by_file_owned(&hovered).unwrap_or_default();
let mime = cx.mgr.mimetype.owned(&hovered.url).unwrap_or_default();
let folder = cx.tab().hovered_folder().map(|f| (f.offset, f.cha));
if !cx.tab().preview.same_url(&hovered.url) {

View file

@ -2,13 +2,12 @@ use std::{ffi::OsString, time::Duration};
use anyhow::Result;
use tokio::{select, time};
use yazi_boot::ARGS;
use yazi_config::popup::ConfirmCfg;
use yazi_dds::spark::SparkKind;
use yazi_macro::{emit, succ};
use yazi_parser::mgr::{OpenOpt, QuitOpt};
use yazi_parser::mgr::QuitOpt;
use yazi_proxy::ConfirmProxy;
use yazi_shared::{event::{Data, EventQuit}, url::UrlBuf};
use yazi_shared::{data::Data, event::EventQuit, url::UrlCow};
use crate::{Actor, Ctx};
@ -67,21 +66,17 @@ impl Actor for Quit {
}
impl Quit {
pub(super) fn quit_with_selected<'a, I>(opt: OpenOpt, selected: I) -> bool
pub(super) fn with_selected<'a, I, T>(selected: I)
where
I: Iterator<Item = &'a UrlBuf>,
I: IntoIterator<Item = T>,
T: Into<UrlCow<'a>>,
{
if opt.interactive || ARGS.chooser_file.is_none() {
return false;
}
let paths = selected.fold(OsString::new(), |mut s, u| {
s.push(u.os_str());
let paths = selected.into_iter().fold(OsString::new(), |mut s, u| {
s.push(u.into().as_url().os_str());
s.push("\n");
s
});
emit!(Quit(EventQuit { selected: Some(paths), ..Default::default() }));
true
}
}

View file

@ -5,7 +5,7 @@ use yazi_core::tab::Folder;
use yazi_fs::{CWD, Files, FilesOp, cha::Cha};
use yazi_macro::{act, succ};
use yazi_parser::VoidOpt;
use yazi_shared::{event::Data, url::UrlBuf};
use yazi_shared::{data::Data, url::UrlBuf};
use yazi_term::tty::TTY;
use yazi_vfs::{VfsFiles, VfsFilesOp};

View file

@ -3,7 +3,7 @@ use yazi_config::popup::ConfirmCfg;
use yazi_macro::{act, succ};
use yazi_parser::mgr::RemoveOpt;
use yazi_proxy::{ConfirmProxy, MgrProxy};
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -1,11 +1,11 @@
use anyhow::Result;
use yazi_config::popup::{ConfirmCfg, InputCfg};
use yazi_dds::Pubsub;
use yazi_fs::{File, FilesOp, ok_or_not_found};
use yazi_macro::{act, err, succ};
use yazi_fs::{File, FilesOp};
use yazi_macro::{act, err, ok_or_not_found, succ};
use yazi_parser::mgr::RenameOpt;
use yazi_proxy::{ConfirmProxy, InputProxy, MgrProxy};
use yazi_shared::{Id, event::Data, url::UrlBuf};
use yazi_shared::{Id, data::Data, url::UrlBuf};
use yazi_vfs::{VfsFile, maybe_exists, provider};
use yazi_watcher::WATCHER;
@ -72,7 +72,7 @@ impl Rename {
if let Ok(u) = overwritten
&& let Some((parent, urn)) = u.pair()
{
ok_or_not_found(provider::rename(&u, &new).await)?;
ok_or_not_found!(provider::rename(&u, &new).await);
FilesOp::Deleting(parent.to_owned(), [urn.into()].into()).emit();
}

View file

@ -2,7 +2,7 @@ use anyhow::Result;
use yazi_fs::{File, FilesOp};
use yazi_macro::{act, render, succ};
use yazi_parser::mgr::RevealOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -9,7 +9,7 @@ use yazi_macro::{act, succ};
use yazi_parser::{VoidOpt, mgr::{SearchOpt, SearchOptVia}};
use yazi_plugin::external;
use yazi_proxy::{InputProxy, MgrProxy};
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -3,7 +3,7 @@ use yazi_config::YAZI;
use yazi_macro::succ;
use yazi_parser::mgr::SeekOpt;
use yazi_plugin::isolate;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};
@ -19,11 +19,11 @@ impl Actor for Seek {
succ!(cx.tab_mut().preview.reset());
};
let Some(mime) = cx.mgr.mimetype.by_file(hovered) else {
let Some(mime) = cx.mgr.mimetype.get(&hovered.url) else {
succ!(cx.tab_mut().preview.reset());
};
let Some(previewer) = YAZI.plugin.previewer(&hovered.url, mime) else {
let Some(previewer) = YAZI.plugin.previewer(hovered, mime) else {
succ!(cx.tab_mut().preview.reset());
};

View file

@ -5,7 +5,7 @@ use yazi_config::{opener::OpenerRule, popup::InputCfg};
use yazi_macro::{act, succ};
use yazi_parser::mgr::ShellOpt;
use yazi_proxy::{InputProxy, TasksProxy};
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};
@ -20,7 +20,7 @@ impl Actor for Shell {
act!(mgr:escape_visual, cx)?;
let cwd = opt.cwd.take().unwrap_or(cx.cwd().into()).into_owned();
let selected = cx.tab().hovered_and_selected().cloned().collect();
let selected = cx.tab().hovered_and_selected().cloned().map(Into::into).collect();
let input = opt.interactive.then(|| {
InputProxy::show(InputCfg::shell(opt.block).with_value(&*opt.run).with_cursor(opt.cursor))

View file

@ -3,7 +3,7 @@ use yazi_core::tab::Folder;
use yazi_fs::{FilesSorter, FolderStage};
use yazi_macro::{act, render, render_and, succ};
use yazi_parser::mgr::SortOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::succ;
use yazi_parser::mgr::SpotOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};
@ -15,7 +15,7 @@ impl Actor for Spot {
fn act(cx: &mut Ctx, opt: Self::Options) -> Result<Data> {
let Some(hovered) = cx.hovered().cloned() else { succ!() };
let mime = cx.mgr.mimetype.by_file_owned(&hovered).unwrap_or_default();
let mime = cx.mgr.mimetype.owned(&hovered.url).unwrap_or_default();
// if !self.active().spot.same_file(&hovered, &mime) {
// self.active_mut().spot.reset();
// }

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::succ;
use yazi_parser::VoidOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::{act, render, succ};
use yazi_parser::mgr::TabCloseOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -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::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -2,7 +2,7 @@ use anyhow::Result;
use yazi_dds::Pubsub;
use yazi_macro::{err, render, succ};
use yazi_parser::ArrowOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::{act, render, succ};
use yazi_parser::mgr::TabSwitchOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -2,7 +2,7 @@ use anyhow::Result;
use yazi_macro::{render_and, succ};
use yazi_parser::mgr::ToggleOpt;
use yazi_proxy::AppProxy;
use yazi_shared::{event::Data, url::UrlCow};
use yazi_shared::{data::Data, url::UrlCow};
use crate::{Actor, Ctx};

View file

@ -2,7 +2,7 @@ use anyhow::Result;
use yazi_macro::{render, succ};
use yazi_parser::mgr::ToggleAllOpt;
use yazi_proxy::AppProxy;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::{act, render, succ};
use yazi_parser::VoidOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::Actor;

View file

@ -3,7 +3,7 @@ use yazi_core::tab::Folder;
use yazi_fs::FilesOp;
use yazi_macro::{act, render, succ};
use yazi_parser::mgr::UpdateFilesOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use yazi_watcher::LINKED;
use crate::{Actor, Ctx};

View file

@ -2,7 +2,7 @@ use anyhow::Result;
use hashbrown::HashMap;
use yazi_macro::{act, render, succ};
use yazi_parser::mgr::UpdateMimesOpt;
use yazi_shared::{event::Data, pool::InternStr, url::UrlCov};
use yazi_shared::{data::Data, pool::InternStr, url::UrlCov};
use yazi_watcher::LINKED;
use crate::{Actor, Ctx};
@ -20,7 +20,7 @@ impl Actor for UpdateMimes {
.updates
.into_iter()
.flat_map(|(key, value)| key.into_url().zip(value.into_string()))
.filter(|(url, mime)| cx.mgr.mimetype.by_url(url) != Some(mime))
.filter(|(url, mime)| cx.mgr.mimetype.get(url) != Some(mime))
.fold(HashMap::new(), |mut map, (u, m)| {
for u in linked.from_file(u.as_url()) {
map.insert(u.into(), m.intern());

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::succ;
use yazi_parser::mgr::UpdatePagedOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::{render, succ};
use yazi_parser::mgr::UpdatePeekedOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::Actor;

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::{render, succ};
use yazi_parser::mgr::UpdateSpottedOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -2,7 +2,7 @@ use anyhow::Result;
use yazi_core::mgr::Yanked;
use yazi_macro::{render, succ};
use yazi_parser::mgr::UpdateYankedOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -4,7 +4,7 @@ use anyhow::Result;
use yazi_core::tab::Mode;
use yazi_macro::{render, succ};
use yazi_parser::mgr::VisualModeOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -3,7 +3,7 @@ use std::iter;
use anyhow::Result;
use yazi_macro::succ;
use yazi_parser::VoidOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -2,7 +2,7 @@ use anyhow::Result;
use yazi_core::mgr::Yanked;
use yazi_macro::{act, render};
use yazi_parser::mgr::YankOpt;
use yazi_shared::{event::Data, url::UrlBufCov};
use yazi_shared::{data::Data, url::UrlBufCov};
use crate::{Actor, Ctx};

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::{render, succ};
use yazi_parser::ArrowOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use yazi_widgets::Scrollable;
use crate::{Actor, Ctx};

View file

@ -1,7 +1,7 @@
use anyhow::{Result, anyhow};
use yazi_macro::{render, succ};
use yazi_parser::pick::CloseOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::{act, render, succ};
use yazi_parser::pick::ShowOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::{act, render, succ};
use yazi_parser::ArrowOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::succ;
use yazi_parser::VoidOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::succ;
use yazi_parser::spot::CopyOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use yazi_widgets::CLIPBOARD;
use crate::{Actor, Ctx};

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::act;
use yazi_parser::ArrowOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -2,7 +2,7 @@ use anyhow::Result;
use yazi_core::tasks::Tasks;
use yazi_macro::{render, succ};
use yazi_parser::ArrowOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::{act, render, succ};
use yazi_parser::VoidOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::{act, render, succ};
use yazi_parser::VoidOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -7,7 +7,7 @@ use tokio::{io::{AsyncReadExt, stdin}, select, sync::mpsc, time};
use yazi_macro::succ;
use yazi_parser::VoidOpt;
use yazi_proxy::{AppProxy, HIDER};
use yazi_shared::{event::Data, terminal_clear};
use yazi_shared::{data::Data, terminal_clear};
use yazi_term::tty::TTY;
use crate::{Actor, Ctx};

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::succ;
use yazi_parser::mgr::OpenWithOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};
@ -16,7 +16,7 @@ impl Actor for OpenWith {
succ!(cx.tasks.process_from_opener(
opt.cwd,
opt.opener,
opt.targets.into_iter().map(|u| u.into_path2().into_os_string()).collect(),
opt.targets.into_iter().map(|u| u.into_os_str2()).collect(),
));
}
}

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::succ;
use yazi_parser::tasks::ProcessExecOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::{act, render, succ};
use yazi_parser::VoidOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::succ;
use yazi_parser::tasks::UpdateSucceedOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::succ;
use yazi_parser::which::CallbackOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -1,7 +1,7 @@
use anyhow::Result;
use yazi_macro::{render, succ};
use yazi_parser::which::ShowOpt;
use yazi_shared::event::Data;
use yazi_shared::data::Data;
use crate::{Actor, Ctx};

View file

@ -1,9 +1,9 @@
use std::{env, ffi::OsStr, fmt::Write, path::Path};
use std::{env, ffi::OsStr, fmt::Write};
use regex::Regex;
use yazi_adapter::Mux;
use yazi_config::YAZI;
use yazi_shared::{timestamp_us, url::UrlBuf};
use yazi_shared::{timestamp_us, url::Url};
use super::Actions;
@ -59,17 +59,17 @@ impl Actions {
writeln!(
s,
" default : {:?}",
YAZI.opener.first(YAZI.open.all(UrlBuf::from(Path::new("f75a.txt")), "text/plain"))
YAZI.opener.first(YAZI.open.all(Url::regular("f75a.txt"), "text/plain"))
)?;
writeln!(
s,
" block-create: {:?}",
YAZI.opener.block(YAZI.open.all(UrlBuf::from(Path::new("bulk-create.txt")), "text/plain"))
YAZI.opener.block(YAZI.open.all(Url::regular("bulk-create.txt"), "text/plain"))
)?;
writeln!(
s,
" block-rename: {:?}",
YAZI.opener.block(YAZI.open.all(UrlBuf::from(Path::new("bulk-rename.txt")), "text/plain"))
YAZI.opener.block(YAZI.open.all(Url::regular("bulk-rename.txt"), "text/plain"))
)?;
writeln!(s, "\nMultiplexers")?;

View file

@ -1,6 +1,7 @@
use anyhow::{Context, Result, bail};
use twox_hash::XxHash3_128;
use yazi_fs::{ok_or_not_found, provider::{DirReader, FileHolder, Provider, local::Local}};
use yazi_fs::provider::{DirReader, FileHolder, Provider, local::Local};
use yazi_macro::ok_or_not_found;
use super::Dependency;
@ -14,7 +15,7 @@ impl Dependency {
for file in files {
h.write(file.as_bytes());
h.write(b"VpvFw9Atb7cWGOdqhZCra634CcJJRlsRl72RbZeV0vpG1\0");
h.write(&ok_or_not_found(Local.read(dir.join(file)).await)?);
h.write(&ok_or_not_found!(Local.read(dir.join(file)).await));
}
let mut assets = vec![];

View file

@ -3,7 +3,7 @@ use std::{path::PathBuf, str::FromStr};
use anyhow::{Context, Result, bail};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use yazi_fs::{Xdg, provider::{Provider, local::Local}};
use yazi_macro::outln;
use yazi_macro::{ok_or_not_found, outln};
use super::Dependency;
@ -15,11 +15,8 @@ pub(crate) struct Package {
impl Package {
pub(crate) async fn load() -> Result<Self> {
Ok(match Local.read_to_string(Self::toml()).await {
Ok(s) => toml::from_str(&s)?,
Err(e) if e.kind() == std::io::ErrorKind::NotFound => Self::default(),
Err(e) => Err(e)?,
})
let s = ok_or_not_found!(Local.read_to_string(Self::toml()).await);
Ok(toml::from_str(&s)?)
}
pub(crate) async fn add_many(&mut self, uses: &[String]) -> Result<()> {

View file

@ -1,7 +1,8 @@
use std::{io, path::Path};
use tokio::io::AsyncWriteExt;
use yazi_fs::{ok_or_not_found, provider::{FileBuilder, Provider, local::{Gate, Local}}};
use yazi_fs::provider::{FileBuilder, Provider, local::{Gate, Local}};
use yazi_macro::ok_or_not_found;
#[inline]
pub async fn must_exists(path: impl AsRef<Path>) -> bool {
@ -18,7 +19,7 @@ pub async fn maybe_exists(path: impl AsRef<Path>) -> bool {
pub async fn copy_and_seal(from: &Path, to: &Path) -> io::Result<()> {
let b = Local.read(from).await?;
ok_or_not_found(remove_sealed(to).await)?;
ok_or_not_found!(remove_sealed(to).await);
let mut file = Gate::default().create_new(true).write(true).truncate(true).open(to).await?;
file.write_all(&b).await?;

View file

@ -34,6 +34,14 @@ edit = [
{ run = 'code %*', orphan = true, desc = "code", for = "windows" },
{ run = 'code -w %*', block = true, desc = "code (block)", for = "windows" },
]
play = [
{ run = 'xdg-open "$1"', desc = "Play", for = "linux" },
{ run = 'open "$@"', desc = "Play", for = "macos" },
{ run = 'start "" "%1"', orphan = true, desc = "Play", for = "windows" },
{ run = 'termux-open "$1"', desc = "Play", for = "android" },
{ run = '''mediainfo "$1"; echo "Press enter to exit"; read _''', block = true, desc = "Show media info", for = "unix" },
{ run = 'mediainfo "%1" & pause', block = true, desc = "Show media info", for = "windows" },
]
open = [
{ run = 'xdg-open "$1"', desc = "Open", for = "linux" },
{ run = 'open "$@"', desc = "Open", for = "macos" },
@ -51,13 +59,11 @@ extract = [
{ run = 'ya pub extract --list "$@"', desc = "Extract here", for = "unix" },
{ run = 'ya pub extract --list %*', desc = "Extract here", for = "windows" },
]
play = [
{ run = 'xdg-open "$1"', desc = "Play", for = "linux" },
{ run = 'open "$@"', desc = "Play", for = "macos" },
{ run = 'start "" "%1"', orphan = true, desc = "Play", for = "windows" },
{ run = 'termux-open "$1"', desc = "Play", for = "android" },
{ run = '''mediainfo "$1"; echo "Press enter to exit"; read _''', block = true, desc = "Show media info", for = "unix" },
{ run = 'mediainfo "%1" & pause', block = true, desc = "Show media info", for = "windows" },
download = [
{ run = 'ya emit download --open "$@"', desc = "Download and open", for = "unix" },
{ run = 'ya emit download --open %*', desc = "Download and open", for = "windows" },
{ run = 'ya emit download "$@"', desc = "Download", for = "unix" },
{ run = 'ya emit download %*', desc = "Download", for = "windows" },
]
[open]
@ -77,6 +83,8 @@ rules = [
{ mime = "*/javascript", use = [ "edit", "reveal" ] },
# Empty file
{ mime = "inode/empty", use = [ "edit", "reveal" ] },
# Virtual file system
{ mime = "vfs/*", use = "download" },
# Fallback
{ url = "*", use = [ "open", "reveal" ] },
]
@ -92,7 +100,8 @@ suppress_preload = false
[plugin]
fetchers = [
# Mimetype
{ id = "mime", url = "*", run = "mime", prio = "high" },
{ id = "mime", url = "*/", run = "mime.dir", prio = "high" },
{ id = "mime", url = "*", run = "mime.file", prio = "high" },
]
spotters = [
{ url = "*/", run = "folder" },

View file

@ -4,7 +4,7 @@ use anyhow::Result;
use indexmap::IndexSet;
use serde::Deserialize;
use yazi_codegen::DeserializeOver2;
use yazi_shared::{MIME_DIR, url::UrlBuf};
use yazi_shared::url::AsUrl;
use crate::{Preset, open::OpenRule};
@ -24,30 +24,31 @@ impl Deref for Open {
}
impl Open {
pub fn all<'a, 'b, P, M>(&'a self, url: P, mime: M) -> impl Iterator<Item = &'a str> + 'b
pub fn all<'a, 'b, U, M>(&'a self, url: U, mime: M) -> impl Iterator<Item = &'a str> + 'b
where
'a: 'b,
P: AsRef<UrlBuf> + 'b,
U: AsUrl + 'b,
M: AsRef<str> + 'b,
{
let is_dir = mime.as_ref() == MIME_DIR;
let is_dir = mime.as_ref().starts_with("folder/");
self
.rules
.iter()
.filter(move |&r| {
r.mime.as_ref().is_some_and(|p| p.match_mime(&mime))
|| r.url.as_ref().is_some_and(|p| p.match_url(&url, is_dir))
|| r.url.as_ref().is_some_and(|p| p.match_url(url.as_url(), is_dir))
})
.flat_map(|r| &r.r#use)
.map(String::as_str)
}
pub fn common<'a>(
&'a self,
targets: &[(impl AsRef<UrlBuf>, impl AsRef<str>)],
) -> IndexSet<&'a str> {
pub fn common<'a, 'b, U, M>(&'a self, targets: &'b [(U, M)]) -> IndexSet<&'a str>
where
&'b U: AsUrl,
M: AsRef<str>,
{
let each: Vec<IndexSet<&str>> = targets
.iter()
.into_iter()
.map(|(u, m)| self.all(u, m).collect::<IndexSet<_>>())
.filter(|s| !s.is_empty())
.collect();

View file

@ -3,7 +3,7 @@ use std::str::FromStr;
use anyhow::Result;
use globset::GlobBuilder;
use serde::Deserialize;
use yazi_shared::{scheme::{SchemeCow, SchemeRef}, url::UrlBuf};
use yazi_shared::{scheme::{SchemeCow, SchemeRef}, url::Url};
#[derive(Debug, Deserialize)]
#[serde(try_from = "String")]
@ -17,14 +17,14 @@ pub struct Pattern {
}
impl Pattern {
pub fn match_url(&self, url: impl AsRef<UrlBuf>, is_dir: bool) -> bool {
let url = url.as_ref();
pub fn match_url<'a>(&self, url: impl Into<Url<'a>>, is_dir: bool) -> bool {
let url = url.into();
if is_dir != self.is_dir {
return false;
} else if self.is_star {
return true;
} else if !self.scheme.matches(&url.scheme) {
} else if !self.scheme.matches(url.scheme) {
return false;
}
@ -121,10 +121,12 @@ impl PatternScheme {
// --- Tests
#[cfg(test)]
mod tests {
use yazi_shared::url::UrlCow;
use super::*;
fn matches(glob: &str, url: &str) -> bool {
Pattern::from_str(glob).unwrap().match_url(UrlBuf::from_str(url).unwrap(), false)
Pattern::from_str(glob).unwrap().match_url(&UrlCow::try_from(url).unwrap(), false)
}
#[cfg(unix)]

View file

@ -1,5 +1,6 @@
use serde::Deserialize;
use yazi_shared::{MIME_DIR, event::Cmd, url::UrlBuf};
use yazi_fs::File;
use yazi_shared::event::Cmd;
use crate::{Pattern, Priority};
@ -18,8 +19,8 @@ pub struct Fetcher {
impl Fetcher {
#[inline]
pub fn matches(&self, url: &UrlBuf, mime: &str) -> bool {
pub fn matches(&self, file: &File, mime: &str) -> bool {
self.mime.as_ref().is_some_and(|p| p.match_mime(mime))
|| self.url.as_ref().is_some_and(|p| p.match_url(url, mime == MIME_DIR))
|| self.url.as_ref().is_some_and(|p| p.match_url(&file.url, file.is_dir()))
}
}

View file

@ -4,7 +4,6 @@ use serde::Deserialize;
use tracing::warn;
use yazi_codegen::DeserializeOver2;
use yazi_fs::File;
use yazi_shared::url::UrlBuf;
use super::{Fetcher, Preloader, Previewer, Spotter};
use crate::{Preset, plugin::MAX_PREWORKERS};
@ -39,12 +38,12 @@ pub struct Plugin {
impl Plugin {
pub fn fetchers<'a, 'b: 'a>(
&'b self,
url: &'a UrlBuf,
file: &'a File,
mime: &'a str,
) -> impl Iterator<Item = &'b Fetcher> + 'a {
let mut seen = HashSet::new();
self.fetchers.iter().filter(move |&f| {
if seen.contains(&f.id) || !f.matches(url, mime) {
if seen.contains(&f.id) || !f.matches(file, mime) {
return false;
}
seen.insert(&f.id);
@ -55,7 +54,7 @@ impl Plugin {
pub fn mime_fetchers(&self, files: Vec<File>) -> impl Iterator<Item = (&Fetcher, Vec<File>)> {
let mut tasks: [Vec<_>; MAX_PREWORKERS as usize] = Default::default();
for f in files {
let found = self.fetchers.iter().find(|&g| g.id == "mime" && g.matches(&f.url, ""));
let found = self.fetchers.iter().find(|&g| g.id == "mime" && g.matches(&f, ""));
if let Some(g) = found {
tasks[g.idx as usize].push(f);
} else {
@ -68,18 +67,18 @@ impl Plugin {
})
}
pub fn spotter(&self, url: &UrlBuf, mime: &str) -> Option<&Spotter> {
self.spotters.iter().find(|&p| p.matches(url, mime))
pub fn spotter(&self, file: &File, mime: &str) -> Option<&Spotter> {
self.spotters.iter().find(|&p| p.matches(file, mime))
}
pub fn preloaders<'a, 'b: 'a>(
&'b self,
url: &'a UrlBuf,
file: &'a File,
mime: &'a str,
) -> impl Iterator<Item = &'b Preloader> + 'a {
let mut next = true;
self.preloaders.iter().filter(move |&p| {
if !next || !p.matches(url, mime) {
if !next || !p.matches(file, mime) {
return false;
}
next = p.next;
@ -87,8 +86,8 @@ impl Plugin {
})
}
pub fn previewer(&self, url: &UrlBuf, mime: &str) -> Option<&Previewer> {
self.previewers.iter().find(|&p| p.matches(url, mime))
pub fn previewer(&self, file: &File, mime: &str) -> Option<&Previewer> {
self.previewers.iter().find(|&p| p.matches(file, mime))
}
}

View file

@ -1,5 +1,6 @@
use serde::Deserialize;
use yazi_shared::{MIME_DIR, event::Cmd, url::UrlBuf};
use yazi_fs::File;
use yazi_shared::event::Cmd;
use crate::{Pattern, Priority};
@ -19,8 +20,8 @@ pub struct Preloader {
impl Preloader {
#[inline]
pub fn matches(&self, url: &UrlBuf, mime: &str) -> bool {
pub fn matches(&self, file: &File, mime: &str) -> bool {
self.mime.as_ref().is_some_and(|p| p.match_mime(mime))
|| self.url.as_ref().is_some_and(|p| p.match_url(url, mime == MIME_DIR))
|| self.url.as_ref().is_some_and(|p| p.match_url(&file.url, file.is_dir()))
}
}

Some files were not shown because too many files have changed in this diff Show more