use std::{collections::BTreeMap, path::Path}; use indexmap::IndexSet; use serde::{Deserialize, Deserializer}; use shared::MIME_DIR; use super::Opener; use crate::{open::OpenRule, MERGED_YAZI}; #[derive(Debug)] pub struct Open { rules: Vec, openers: BTreeMap>, } impl Default for Open { fn default() -> Self { toml::from_str(&MERGED_YAZI).unwrap() } } impl Open { pub fn openers(&self, path: P, mime: M) -> Option> where P: AsRef, M: AsRef, { let is_folder = Some(mime.as_ref() == MIME_DIR); self.rules.iter().find_map(|rule| { if rule.mime.as_ref().is_some_and(|m| m.matches(&mime)) || rule.name.as_ref().is_some_and(|n| n.match_path(&path, is_folder)) { let openers = rule .use_ .iter() .filter_map(|use_| self.openers.get(use_)) .flatten() .collect::>(); if openers.is_empty() { None } else { Some(openers) } } else { None } }) } #[inline] pub fn block_opener(&self, path: P, mime: M) -> Option<&Opener> where P: AsRef, M: AsRef, { 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: 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() } } impl<'de> Deserialize<'de> for Open { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { #[derive(Deserialize)] struct Outer { opener: BTreeMap>, open: OuterOpen, } #[derive(Deserialize)] struct OuterOpen { rules: Vec, } let outer = Outer::deserialize(deserializer)?; let openers = outer .opener .into_iter() .map(|(k, v)| (k, v.into_iter().filter_map(|o| o.take()).collect::>())) .collect(); Ok(Self { rules: outer.open.rules, openers }) } }