From 8e72ae90c1ef56e50191cfa1a8db30beb68065f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E5=92=B2=E9=9B=85=20=C2=B7=20Misaki=20Masa?= Date: Sun, 17 Sep 2023 01:29:44 +0800 Subject: [PATCH 1/5] fix: check relative path on `expand_path` (#165) --- core/src/files/sorter.rs | 2 +- shared/src/fns.rs | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/core/src/files/sorter.rs b/core/src/files/sorter.rs index 5149a9ac..386d1bf8 100644 --- a/core/src/files/sorter.rs +++ b/core/src/files/sorter.rs @@ -1,4 +1,4 @@ -use std::{cmp::Ordering, collections::BTreeMap, mem, ops::Deref}; +use std::{cmp::Ordering, collections::BTreeMap, mem}; use config::{manager::SortBy, MANAGER}; use shared::Url; diff --git a/shared/src/fns.rs b/shared/src/fns.rs index 63b3cf96..5b915a98 100644 --- a/shared/src/fns.rs +++ b/shared/src/fns.rs @@ -11,7 +11,10 @@ pub fn expand_path(p: impl AsRef) -> PathBuf { return PathBuf::from_iter([&home, p.as_os_str()]); } } - p.to_path_buf() + if p.is_absolute() { + return p.to_path_buf(); + } + env::current_dir().map_or_else(|_| p.to_path_buf(), |c| c.join(p)) } #[inline] From a04faa9dbcb4bb6213c2336b71cc72241066aa2f Mon Sep 17 00:00:00 2001 From: yggdr Date: Sun, 17 Sep 2023 01:16:49 +0200 Subject: [PATCH 2/5] feat: support for FreeBSD permission type (#169) --- shared/src/fs.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/shared/src/fs.rs b/shared/src/fs.rs index 72c7058f..2236dbc2 100644 --- a/shared/src/fs.rs +++ b/shared/src/fs.rs @@ -99,6 +99,8 @@ pub fn file_mode(mode: u32) -> String { #[cfg(target_os = "macos")] let m = mode as u16; + #[cfg(target_os = "freebsd")] + let m = mode as u16; #[cfg(target_os = "linux")] let m = mode; From 09243716a980eb5548704f572eecb23f686d23fa Mon Sep 17 00:00:00 2001 From: Linus <23507341+Linus789@users.noreply.github.com> Date: Sat, 16 Sep 2023 23:20:04 +0000 Subject: [PATCH 3/5] feat: multiple openers for a single rule (#154) --- config/docs/yazi.md | 3 +++ config/src/open/mod.rs | 2 ++ config/src/open/open.rs | 27 +++++++++---------- config/src/open/rule.rs | 58 +++++++++++++++++++++++++++++++++++++++++ core/src/tasks/tasks.rs | 2 +- 5 files changed, 77 insertions(+), 15 deletions(-) create mode 100644 config/src/open/rule.rs diff --git a/config/docs/yazi.md b/config/docs/yazi.md index 0c609692..fabc07b2 100644 --- a/config/docs/yazi.md +++ b/config/docs/yazi.md @@ -81,6 +81,9 @@ rules = [ # { mime = "application/json", use = "text" }, { name = "*.json", use = "text" }, + + # Multiple openers for a single rule + { name = "*.html", use = [ "browser", "text" ] }, ] ``` diff --git a/config/src/open/mod.rs b/config/src/open/mod.rs index 5aea8dfe..085ff005 100644 --- a/config/src/open/mod.rs +++ b/config/src/open/mod.rs @@ -1,5 +1,7 @@ mod open; mod opener; +mod rule; pub use open::*; pub use opener::*; +use rule::*; diff --git a/config/src/open/open.rs b/config/src/open/open.rs index 8575301c..879b6b3b 100644 --- a/config/src/open/open.rs +++ b/config/src/open/open.rs @@ -5,7 +5,7 @@ use serde::{Deserialize, Deserializer}; use shared::MIME_DIR; use super::Opener; -use crate::{Pattern, MERGED_YAZI}; +use crate::{open::OpenRule, MERGED_YAZI}; #[derive(Debug)] pub struct Open { @@ -13,20 +13,12 @@ pub struct Open { rules: Vec, } -#[derive(Debug, Deserialize)] -struct OpenRule { - name: Option, - mime: Option, - #[serde(rename = "use")] - use_: String, -} - impl Default for Open { fn default() -> Self { toml::from_str(&MERGED_YAZI).unwrap() } } impl Open { - pub fn openers(&self, path: P, mime: M) -> Option<&IndexSet> + pub fn openers(&self, path: P, mime: M) -> Option> where P: AsRef, M: AsRef, @@ -36,7 +28,14 @@ impl Open { if rule.mime.as_ref().map_or(false, |m| m.matches(&mime)) || rule.name.as_ref().map_or(false, |n| n.match_path(&path, is_folder)) { - self.openers.get(&rule.use_) + let openers = rule + .use_ + .iter() + .filter_map(|use_| self.openers.get(use_)) + .flatten() + .collect::>(); + + if openers.is_empty() { None } else { Some(openers) } } else { None } @@ -49,12 +48,12 @@ impl Open { P: AsRef, M: AsRef, { - self.openers(path, mime).and_then(|o| o.iter().find(|o| o.block)) + self.openers(path, mime).and_then(|o| o.into_iter().find(|o| o.block)) } pub fn common_openers(&self, targets: &[(impl AsRef, impl AsRef)]) -> Vec<&Opener> { - let grouped = targets.iter().filter_map(|(p, m)| self.openers(p, m)).collect::>(); - let flat = grouped.iter().flat_map(|&g| g).collect::>(); + let grouped: Vec<_> = targets.iter().filter_map(|(p, m)| self.openers(p, m)).collect(); + let flat: IndexSet<_> = grouped.iter().flatten().copied().collect(); flat.into_iter().filter(|&o| grouped.iter().all(|g| g.contains(o))).collect() } } diff --git a/config/src/open/rule.rs b/config/src/open/rule.rs new file mode 100644 index 00000000..f4ce3daa --- /dev/null +++ b/config/src/open/rule.rs @@ -0,0 +1,58 @@ +use std::fmt; + +use serde::{de::{self, Visitor}, Deserialize, Deserializer}; + +use crate::pattern::Pattern; + +#[derive(Debug, Deserialize)] +pub(super) struct OpenRule { + pub(super) name: Option, + pub(super) mime: Option, + #[serde(rename = "use")] + #[serde(deserialize_with = "OpenRule::deserialize")] + pub(super) use_: Vec, +} + +impl OpenRule { + fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + { + struct UseVisitor; + + impl<'de> Visitor<'de> for UseVisitor { + type Value = Vec; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a string, or array of strings") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: de::SeqAccess<'de>, + { + let mut uses = Vec::new(); + while let Some(use_) = seq.next_element::()? { + uses.push(use_); + } + Ok(uses) + } + + fn visit_str(self, value: &str) -> Result + where + E: de::Error, + { + Ok(vec![value.to_owned()]) + } + + fn visit_string(self, v: String) -> Result + where + E: de::Error, + { + Ok(vec![v]) + } + } + + deserializer.deserialize_any(UseVisitor) + } +} diff --git a/core/src/tasks/tasks.rs b/core/src/tasks/tasks.rs index c75ec048..f11de926 100644 --- a/core/src/tasks/tasks.rs +++ b/core/src/tasks/tasks.rs @@ -134,7 +134,7 @@ impl Tasks { pub fn file_open(&self, targets: &[(impl AsRef, impl AsRef)]) -> bool { let mut openers = BTreeMap::new(); for (path, mime) in targets { - if let Some(opener) = OPEN.openers(path, mime).and_then(|o| o.first()) { + if let Some(opener) = OPEN.openers(path, mime).and_then(|o| o.first().copied()) { openers.entry(opener).or_insert_with(Vec::new).push(path.as_ref().as_os_str()); } } From 07d5df05f18b804992d2928e7722da0c3fa88790 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E5=92=B2=E9=9B=85=20=C2=B7=20Misaki=20Masa?= Date: Sun, 17 Sep 2023 15:23:01 +0800 Subject: [PATCH 4/5] fix: leave upwards only if an IO error occurs in `current` (#172) --- core/src/manager/manager.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/core/src/manager/manager.rs b/core/src/manager/manager.rs index f83e4807..e8e8f881 100644 --- a/core/src/manager/manager.rs +++ b/core/src/manager/manager.rs @@ -362,14 +362,13 @@ impl Manager { if url == self.cwd() { self.current_mut().update(op); + self.active_mut().leave(); + true } else if matches!(self.parent(), Some(p) if &p.cwd == url) { - self.active_mut().parent.as_mut().unwrap().update(op); + self.active_mut().parent.as_mut().unwrap().update(op) } else { - return false; + false } - - self.active_mut().leave(); - true } pub fn update_mimetype(&mut self, mut mimes: BTreeMap, tasks: &Tasks) -> bool { From ba3f603de4fc356550a74982484cd4a5699ffda6 Mon Sep 17 00:00:00 2001 From: Ctem <26450958+ctem@users.noreply.github.com> Date: Sun, 17 Sep 2023 17:50:16 +0900 Subject: [PATCH 5/5] feat: tab switch wraparound (#160) --- core/src/manager/tabs.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/src/manager/tabs.rs b/core/src/manager/tabs.rs index 33d978cc..01d09cf7 100644 --- a/core/src/manager/tabs.rs +++ b/core/src/manager/tabs.rs @@ -33,7 +33,11 @@ impl Tabs { } pub fn switch(&mut self, idx: isize, rel: bool) -> bool { - let idx = if rel { self.absolute(idx) } else { idx as usize }; + let idx = if rel { + (self.idx as isize + idx).rem_euclid(self.items.len() as isize) as usize + } else { + idx as usize + }; if idx == self.idx || idx >= self.items.len() { return false;