Refactor the open command

This commit is contained in:
sxyazi 2024-02-14 22:04:40 +08:00
parent 9fe0c1bdb7
commit 9788e53f5c
No known key found for this signature in database
7 changed files with 54 additions and 27 deletions

View file

@ -317,7 +317,7 @@ impl Files {
impl Files { impl Files {
// --- Items // --- Items
#[inline] #[inline]
pub fn position(&self, url: &Url) -> Option<usize> { self.iter().position(|f| &f.url == url) } pub fn position(&self, url: &Url) -> Option<usize> { self.iter().position(|f| f.url == *url) }
// --- Ticket // --- Ticket
#[inline] #[inline]

View file

@ -5,10 +5,10 @@ use yazi_config::{popup::SelectCfg, ARGS, OPEN};
use yazi_plugin::isolate; use yazi_plugin::isolate;
use yazi_shared::{emit, event::{Cmd, EventQuit}, fs::{File, Url}, Layer, MIME_DIR}; use yazi_shared::{emit, event::{Cmd, EventQuit}, fs::{File, Url}, Layer, MIME_DIR};
use crate::{manager::Manager, select::Select, tasks::Tasks}; use crate::{folder::Folder, manager::Manager, select::Select, tasks::Tasks};
pub struct Opt { pub struct Opt {
targets: Vec<(Url, Option<String>)>, targets: Vec<(Url, String)>,
interactive: bool, interactive: bool,
} }
@ -23,7 +23,7 @@ impl From<Cmd> for Opt {
impl Manager { impl Manager {
pub fn open(&mut self, opt: impl Into<Opt>, tasks: &Tasks) { pub fn open(&mut self, opt: impl Into<Opt>, tasks: &Tasks) {
let selected = self.selected(); let selected = self.selected_or_hovered();
if selected.is_empty() { if selected.is_empty() {
return; return;
} else if Self::quit_with_selected(&selected) { } else if Self::quit_with_selected(&selected) {
@ -31,13 +31,13 @@ impl Manager {
} }
let (mut done, mut todo) = (Vec::with_capacity(selected.len()), vec![]); let (mut done, mut todo) = (Vec::with_capacity(selected.len()), vec![]);
for f in selected { for u in selected {
if f.is_dir() { if self.mimetype.get(u).is_some() {
done.push((f.url(), Some(MIME_DIR.to_owned()))); done.push((u.clone(), String::new()));
} else if self.mimetype.get(&f.url).is_some() { } else if self.guess_its_folder(u) {
done.push((f.url(), None)); done.push((u.clone(), MIME_DIR.to_owned()));
} else { } else {
todo.push(f.clone()); todo.push(u.clone());
} }
} }
@ -48,8 +48,15 @@ impl Manager {
} }
tokio::spawn(async move { tokio::spawn(async move {
done.extend(todo.iter().map(|f| (f.url(), None))); let mut files = Vec::with_capacity(todo.len());
if let Err(e) = isolate::preload("mime", todo, true).await { for u in todo {
if let Ok(f) = File::from(u).await {
files.push(f);
}
}
done.extend(files.iter().map(|f| (f.url(), String::new())));
if let Err(e) = isolate::preload("mime", files, true).await {
error!("preload in watcher failed: {e}"); error!("preload in watcher failed: {e}");
} }
@ -58,7 +65,7 @@ impl Manager {
} }
#[inline] #[inline]
pub fn _open_do(interactive: bool, targets: Vec<(Url, Option<String>)>) { pub fn _open_do(interactive: bool, targets: Vec<(Url, String)>) {
emit!(Call( emit!(Call(
Cmd::new("open_do").with_bool("interactive", interactive).with_data(targets), Cmd::new("open_do").with_bool("interactive", interactive).with_data(targets),
Layer::Manager Layer::Manager
@ -74,7 +81,9 @@ impl Manager {
let targets: Vec<_> = opt let targets: Vec<_> = opt
.targets .targets
.into_iter() .into_iter()
.filter_map(|(u, m)| m.or_else(|| self.mimetype.get(&u).cloned()).map(|m| (u, m))) .filter_map(|(u, m)| {
Some(m).filter(|m| !m.is_empty()).or_else(|| self.mimetype.get(&u).cloned()).map(|m| (u, m))
})
.collect(); .collect();
if targets.is_empty() { if targets.is_empty() {
@ -98,13 +107,30 @@ impl Manager {
}); });
} }
fn quit_with_selected(selected: &[&File]) -> bool { fn guess_its_folder(&self, url: &Url) -> bool {
let Some(p) = url.parent_url() else {
return true;
};
let find = |folder: Option<&Folder>| {
folder.is_some_and(|folder| {
folder.cwd == p && folder.files.iter().any(|f| f.is_dir() && f.url == *url)
})
};
find(Some(self.current()))
|| find(self.parent())
|| find(self.hovered_folder())
|| find(self.active().history.get(&p))
}
fn quit_with_selected(selected: &[&Url]) -> bool {
if ARGS.chooser_file.is_none() { if ARGS.chooser_file.is_none() {
return false; return false;
} }
let paths = selected.iter().fold(OsString::new(), |mut s, &f| { let paths = selected.iter().fold(OsString::new(), |mut s, &u| {
s.push(f.url.as_os_str()); s.push(u.as_os_str());
s.push("\n"); s.push("\n");
s s
}); });

View file

@ -35,11 +35,7 @@ impl Manager {
return render!(self.active_mut().preview.reset()); return render!(self.active_mut().preview.reset());
}; };
let folder = Some(()) let folder = self.active().hovered_folder().map(|f| (f.offset, f.mtime));
.filter(|_| hovered.is_dir())
.and_then(|_| self.active().history.get(&hovered.url))
.map(|f| (f.offset, f.mtime));
if !self.active().preview.same_url(&hovered.url) { if !self.active().preview.same_url(&hovered.url) {
self.active_mut().preview.skip = folder.map(|f| f.0).unwrap_or_default(); self.active_mut().preview.skip = folder.map(|f| f.0).unwrap_or_default();
render!(self.active_mut().preview.reset()); render!(self.active_mut().preview.reset());

View file

@ -47,6 +47,9 @@ impl Manager {
#[inline] #[inline]
pub fn hovered(&self) -> Option<&File> { self.tabs.active().current.hovered() } pub fn hovered(&self) -> Option<&File> { self.tabs.active().current.hovered() }
#[inline]
pub fn hovered_folder(&self) -> Option<&Folder> { self.tabs.active().hovered_folder() }
#[inline] #[inline]
pub fn selected_or_hovered(&self) -> Vec<&Url> { self.tabs.active().selected_or_hovered() } pub fn selected_or_hovered(&self) -> Vec<&Url> { self.tabs.active().selected_or_hovered() }
} }

View file

@ -64,6 +64,11 @@ impl Tab {
self.history.remove(url).unwrap_or_else(|| Folder::from(url)) self.history.remove(url).unwrap_or_else(|| Folder::from(url))
} }
#[inline]
pub fn hovered_folder(&self) -> Option<&Folder> {
self.current.hovered().filter(|&h| h.is_dir()).and_then(|h| self.history.get(&h.url))
}
pub fn apply_files_attrs(&mut self) { pub fn apply_files_attrs(&mut self) {
let apply = |f: &mut Folder| { let apply = |f: &mut Folder| {
if f.stage == FolderStage::Loading { if f.stage == FolderStage::Loading {

View file

@ -26,10 +26,7 @@ impl Preview {
reg.add_field_method_get("skip", |_, me| Ok(me.skip)); reg.add_field_method_get("skip", |_, me| Ok(me.skip));
reg.add_field_method_get("folder", |_, me| { reg.add_field_method_get("folder", |_, me| {
me.tab() me.tab()
.current .hovered_folder()
.hovered()
.filter(|&f| f.is_dir())
.and_then(|f| me.tab().history.get(&f.url))
.map(|f| { .map(|f| {
let limit = LAYOUT.load().preview.height as usize; let limit = LAYOUT.load().preview.height as usize;
Folder::make(Some(me.skip..f.files.len().min(me.skip + limit)), f, me.tab()) Folder::make(Some(me.skip..f.files.len().min(me.skip + limit)), f, me.tab())

View file

@ -46,7 +46,7 @@ struct SelectedIter(btree_set::Iter<'static, yazi_shared::fs::Url>);
impl SelectedIter { impl SelectedIter {
#[inline] #[inline]
fn make(selected: &BTreeSet<yazi_shared::fs::Url>) -> mlua::Result<AnyUserData<'static>> { fn make(selected: &'static BTreeSet<yazi_shared::fs::Url>) -> mlua::Result<AnyUserData<'static>> {
SCOPE.create_any_userdata(Self(selected.iter())) SCOPE.create_any_userdata(Self(selected.iter()))
} }
} }