From 9788e53f5c7b6812c1592848693bebd1f1fe2b70 Mon Sep 17 00:00:00 2001 From: sxyazi Date: Wed, 14 Feb 2024 22:04:40 +0800 Subject: [PATCH] Refactor the `open` command --- yazi-core/src/folder/files.rs | 2 +- yazi-core/src/manager/commands/open.rs | 58 +++++++++++++++++++------- yazi-core/src/manager/commands/peek.rs | 6 +-- yazi-core/src/manager/manager.rs | 3 ++ yazi-core/src/tab/tab.rs | 5 +++ yazi-fm/src/lives/preview.rs | 5 +-- yazi-fm/src/lives/selected.rs | 2 +- 7 files changed, 54 insertions(+), 27 deletions(-) diff --git a/yazi-core/src/folder/files.rs b/yazi-core/src/folder/files.rs index 59837ca3..b4a61acc 100644 --- a/yazi-core/src/folder/files.rs +++ b/yazi-core/src/folder/files.rs @@ -317,7 +317,7 @@ impl Files { impl Files { // --- Items #[inline] - pub fn position(&self, url: &Url) -> Option { self.iter().position(|f| &f.url == url) } + pub fn position(&self, url: &Url) -> Option { self.iter().position(|f| f.url == *url) } // --- Ticket #[inline] diff --git a/yazi-core/src/manager/commands/open.rs b/yazi-core/src/manager/commands/open.rs index 2bbd211e..4e2f2f39 100644 --- a/yazi-core/src/manager/commands/open.rs +++ b/yazi-core/src/manager/commands/open.rs @@ -5,10 +5,10 @@ use yazi_config::{popup::SelectCfg, ARGS, OPEN}; use yazi_plugin::isolate; 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 { - targets: Vec<(Url, Option)>, + targets: Vec<(Url, String)>, interactive: bool, } @@ -23,7 +23,7 @@ impl From for Opt { impl Manager { pub fn open(&mut self, opt: impl Into, tasks: &Tasks) { - let selected = self.selected(); + let selected = self.selected_or_hovered(); if selected.is_empty() { return; } else if Self::quit_with_selected(&selected) { @@ -31,13 +31,13 @@ impl Manager { } let (mut done, mut todo) = (Vec::with_capacity(selected.len()), vec![]); - for f in selected { - if f.is_dir() { - done.push((f.url(), Some(MIME_DIR.to_owned()))); - } else if self.mimetype.get(&f.url).is_some() { - done.push((f.url(), None)); + for u in selected { + if self.mimetype.get(u).is_some() { + done.push((u.clone(), String::new())); + } else if self.guess_its_folder(u) { + done.push((u.clone(), MIME_DIR.to_owned())); } else { - todo.push(f.clone()); + todo.push(u.clone()); } } @@ -48,8 +48,15 @@ impl Manager { } tokio::spawn(async move { - done.extend(todo.iter().map(|f| (f.url(), None))); - if let Err(e) = isolate::preload("mime", todo, true).await { + let mut files = Vec::with_capacity(todo.len()); + 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}"); } @@ -58,7 +65,7 @@ impl Manager { } #[inline] - pub fn _open_do(interactive: bool, targets: Vec<(Url, Option)>) { + pub fn _open_do(interactive: bool, targets: Vec<(Url, String)>) { emit!(Call( Cmd::new("open_do").with_bool("interactive", interactive).with_data(targets), Layer::Manager @@ -74,7 +81,9 @@ impl Manager { let targets: Vec<_> = opt .targets .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(); 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() { return false; } - let paths = selected.iter().fold(OsString::new(), |mut s, &f| { - s.push(f.url.as_os_str()); + let paths = selected.iter().fold(OsString::new(), |mut s, &u| { + s.push(u.as_os_str()); s.push("\n"); s }); diff --git a/yazi-core/src/manager/commands/peek.rs b/yazi-core/src/manager/commands/peek.rs index 8bfdae47..df6d8304 100644 --- a/yazi-core/src/manager/commands/peek.rs +++ b/yazi-core/src/manager/commands/peek.rs @@ -35,11 +35,7 @@ impl Manager { return render!(self.active_mut().preview.reset()); }; - let folder = Some(()) - .filter(|_| hovered.is_dir()) - .and_then(|_| self.active().history.get(&hovered.url)) - .map(|f| (f.offset, f.mtime)); - + let folder = self.active().hovered_folder().map(|f| (f.offset, f.mtime)); if !self.active().preview.same_url(&hovered.url) { self.active_mut().preview.skip = folder.map(|f| f.0).unwrap_or_default(); render!(self.active_mut().preview.reset()); diff --git a/yazi-core/src/manager/manager.rs b/yazi-core/src/manager/manager.rs index 60991764..4250eab4 100644 --- a/yazi-core/src/manager/manager.rs +++ b/yazi-core/src/manager/manager.rs @@ -47,6 +47,9 @@ impl Manager { #[inline] 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] pub fn selected_or_hovered(&self) -> Vec<&Url> { self.tabs.active().selected_or_hovered() } } diff --git a/yazi-core/src/tab/tab.rs b/yazi-core/src/tab/tab.rs index 0a2ba845..f8f1678f 100644 --- a/yazi-core/src/tab/tab.rs +++ b/yazi-core/src/tab/tab.rs @@ -64,6 +64,11 @@ impl Tab { 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) { let apply = |f: &mut Folder| { if f.stage == FolderStage::Loading { diff --git a/yazi-fm/src/lives/preview.rs b/yazi-fm/src/lives/preview.rs index 2e8d07cd..83018ed7 100644 --- a/yazi-fm/src/lives/preview.rs +++ b/yazi-fm/src/lives/preview.rs @@ -26,10 +26,7 @@ impl Preview { reg.add_field_method_get("skip", |_, me| Ok(me.skip)); reg.add_field_method_get("folder", |_, me| { me.tab() - .current - .hovered() - .filter(|&f| f.is_dir()) - .and_then(|f| me.tab().history.get(&f.url)) + .hovered_folder() .map(|f| { let limit = LAYOUT.load().preview.height as usize; Folder::make(Some(me.skip..f.files.len().min(me.skip + limit)), f, me.tab()) diff --git a/yazi-fm/src/lives/selected.rs b/yazi-fm/src/lives/selected.rs index b215bd37..b20233fb 100644 --- a/yazi-fm/src/lives/selected.rs +++ b/yazi-fm/src/lives/selected.rs @@ -46,7 +46,7 @@ struct SelectedIter(btree_set::Iter<'static, yazi_shared::fs::Url>); impl SelectedIter { #[inline] - fn make(selected: &BTreeSet) -> mlua::Result> { + fn make(selected: &'static BTreeSet) -> mlua::Result> { SCOPE.create_any_userdata(Self(selected.iter())) } }