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 0b7c5880..879b6b3b 100644 --- a/config/src/open/open.rs +++ b/config/src/open/open.rs @@ -1,11 +1,11 @@ -use std::{collections::BTreeMap, fmt, path::Path}; +use std::{collections::BTreeMap, path::Path}; use indexmap::IndexSet; -use serde::{de::{self, Visitor}, Deserialize, Deserializer}; +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,15 +13,6 @@ pub struct Open { rules: Vec, } -#[derive(Debug, Deserialize)] -struct OpenRule { - name: Option, - mime: Option, - #[serde(rename = "use")] - #[serde(deserialize_with = "deserialize_from_str_or_vec")] - use_: Vec, -} - impl Default for Open { fn default() -> Self { toml::from_str(&MERGED_YAZI).unwrap() } } @@ -40,15 +31,11 @@ impl Open { let openers = rule .use_ .iter() - .filter_map(|use_name| self.openers.get(use_name)) + .filter_map(|use_| self.openers.get(use_)) .flatten() .collect::>(); - if openers.is_empty() { - return None; - } - - Some(openers) + if openers.is_empty() { None } else { Some(openers) } } else { None } @@ -61,13 +48,13 @@ impl Open { P: AsRef, M: AsRef, { - self.openers(path, mime).and_then(|o| o.iter().find(|o| o.block).copied()) + 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().flatten().collect::>(); - flat.into_iter().filter(|&o| grouped.iter().all(|g| g.contains(o))).copied().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() } } @@ -91,45 +78,3 @@ impl<'de> Deserialize<'de> for Open { Ok(Self { openers, rules: outer.open.rules }) } } - -fn deserialize_from_str_or_vec<'de, D>(deserializer: D) -> Result, D::Error> -where - D: Deserializer<'de>, -{ - struct StringVisitor; - - impl<'de> Visitor<'de> for StringVisitor { - 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 strs = Vec::new(); - while let Some(value) = seq.next_element::()? { - strs.push(value); - } - Ok(strs) - } - - 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(StringVisitor) -} 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 ec7f6e47..f11de926 100644 --- a/core/src/tasks/tasks.rs +++ b/core/src/tasks/tasks.rs @@ -133,12 +133,8 @@ impl Tasks { pub fn file_open(&self, targets: &[(impl AsRef, impl AsRef)]) -> bool { let mut openers = BTreeMap::new(); - let valid_openers = targets - .iter() - .filter_map(|(path, mime)| OPEN.openers(path, mime).map(|o| (path, o))) - .collect::>(); - for (path, opener) in &valid_openers { - if let Some(opener) = opener.first() { + for (path, mime) in targets { + 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()); } }