fix: preserve open order for files with post-resolved mime-types (#2931)

Co-authored-by: TKperson <TKperson@users.noreply.github.com>
Co-authored-by: sxyazi <sxyazi@gmail.com>
This commit is contained in:
TKperson 2025-06-28 18:07:59 +08:00 committed by GitHub
parent 8ef28ec678
commit a8a1b5625b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 35 additions and 29 deletions

View file

@ -1,4 +1,4 @@
use std::borrow::Cow; use std::{borrow::Cow, iter};
use tracing::error; use tracing::error;
use yazi_config::{YAZI, popup::PickCfg}; use yazi_config::{YAZI, popup::PickCfg};
@ -31,57 +31,60 @@ impl Mgr {
return; return;
}; };
let selected = if opt.hovered { vec![&hovered] } else { self.selected_or_hovered().collect() }; let mut selected =
if Self::quit_with_selected(opt, &selected) { if opt.hovered { Box::new(iter::once(&hovered)) } else { self.selected_or_hovered() };
if Self::quit_with_selected(opt, &mut selected) {
return; return;
} }
let cwd = self.cwd().clone(); let mut todo = vec![];
let (mut done, mut todo) = (Vec::with_capacity(selected.len()), vec![]); let targets: Vec<_> = selected
for u in selected { .cloned()
if self.mimetype.contains(u) { .enumerate()
done.push((u.clone(), "")); .map(|(i, u)| {
} else if self.guess_folder(u) { if self.mimetype.contains(&u) {
done.push((u.clone(), MIME_DIR)); (u, "")
} else { } else if self.guess_folder(&u) {
todo.push(u.clone()); (u, MIME_DIR)
} } else {
} todo.push(i);
(u, "")
}
})
.collect();
let cwd = self.cwd().clone();
if todo.is_empty() { if todo.is_empty() {
return self return self
.open_do(OpenDoOpt { cwd, hovered, targets: done, interactive: opt.interactive }, tasks); .open_do(OpenDoOpt { cwd, hovered, targets, interactive: opt.interactive }, tasks);
} }
tokio::spawn(async move { tokio::spawn(async move {
let mut files = Vec::with_capacity(todo.len()); let mut files = Vec::with_capacity(todo.len());
for u in todo { for i in todo {
if let Ok(f) = File::new(u).await { if let Ok(f) = File::new(targets[i].0.clone()).await {
files.push(f); files.push(f);
} }
} }
done.extend(files.iter().map(|f| (f.url_owned(), "")));
for (fetcher, files) in YAZI.plugin.mime_fetchers(files) { for (fetcher, files) in YAZI.plugin.mime_fetchers(files) {
if let Err(e) = isolate::fetch(CmdCow::from(&fetcher.run), files).await { if let Err(e) = isolate::fetch(CmdCow::from(&fetcher.run), files).await {
error!("Fetch mime failed on opening: {e}"); error!("Fetch mime failed on opening: {e}");
} }
} }
MgrProxy::open_do(OpenDoOpt { cwd, hovered, targets: done, interactive: opt.interactive }); MgrProxy::open_do(OpenDoOpt { cwd, hovered, targets, interactive: opt.interactive });
}); });
} }
#[yazi_codegen::command] #[yazi_codegen::command]
pub fn open_do(&mut self, opt: OpenDoOpt, tasks: &Tasks) { pub fn open_do(&mut self, opt: OpenDoOpt, tasks: &Tasks) {
let targets: Vec<_> = opt let mut targets = opt.targets;
.targets targets.iter_mut().filter(|(_, m)| m.is_empty()).for_each(|(u, m)| {
.into_iter() *m = self.mimetype.by_url(u).unwrap_or_default();
.filter_map(|(u, m)| { });
Some(m).filter(|m| !m.is_empty()).or_else(|| self.mimetype.by_url(&u)).map(|m| (u, m))
})
.collect();
targets.retain(|(_, m)| !m.is_empty());
if targets.is_empty() { if targets.is_empty() {
return; return;
} else if !opt.interactive { } else if !opt.interactive {

View file

@ -74,12 +74,15 @@ impl Mgr {
}); });
} }
pub(super) fn quit_with_selected(opt: super::open::Opt, selected: &[&Url]) -> bool { pub(super) fn quit_with_selected<'a, I>(opt: super::open::Opt, selected: I) -> bool
where
I: Iterator<Item = &'a Url>,
{
if opt.interactive || ARGS.chooser_file.is_none() { if opt.interactive || ARGS.chooser_file.is_none() {
return false; return false;
} }
let paths = selected.iter().fold(OsString::new(), |mut s, &u| { let paths = selected.fold(OsString::new(), |mut s, u| {
s.push(u.as_os_str()); s.push(u.as_os_str());
s.push("\n"); s.push("\n");
s s

View file

@ -87,7 +87,7 @@ impl Tab {
pub fn selected_or_hovered(&self) -> Box<dyn Iterator<Item = &Url> + '_> { pub fn selected_or_hovered(&self) -> Box<dyn Iterator<Item = &Url> + '_> {
if self.selected.is_empty() { if self.selected.is_empty() {
Box::new(self.hovered().map(|h| vec![&h.url]).unwrap_or_default().into_iter()) Box::new(self.hovered().map(|h| &h.url).into_iter())
} else { } else {
Box::new(self.selected.keys()) Box::new(self.selected.keys())
} }