use std::ops::Deref; use anyhow::Result; use indexmap::IndexMap; use serde::Deserialize; use yazi_codegen::DeserializeOver2; use yazi_fs::{cha::ChaType, file::File}; use yazi_shared::url::AsUrl; use yazi_shim::toml::DeserializeOverHook; use crate::{mix, open::{OpenRule, OpenRuleArc, OpenRules}}; #[derive(Default, Deserialize, DeserializeOver2)] pub struct Open { rules: OpenRules, #[serde(default)] prepend_rules: Vec, #[serde(default)] append_rules: Vec, } impl Deref for Open { type Target = OpenRules; fn deref(&self) -> &Self::Target { &self.rules } } impl Open { pub fn match_dummy(&self, url: U, mime: M) -> Option where U: AsUrl, M: AsRef, { let mime = mime.as_ref(); let file = File::from_dummy( url.as_url().to_owned(), Some(if mime.starts_with("folder/") { ChaType::Dir } else { ChaType::File }), ); self.matches(&file, mime) } pub fn match_common(&self, targets: &[(File, &str)]) -> impl Iterator { let mut seen: IndexMap = IndexMap::new(); for (file, mime) in targets { if let Some(rule) = self.matches(file, mime) { *seen.entry(rule).or_default() += 1; } } seen.into_iter().filter(|&(_, count)| count == targets.len()).map(|(rule, _)| rule) } } impl DeserializeOverHook for Open { fn deserialize_over_hook(self) -> Result { let rules: Vec = mix(self.prepend_rules, self.rules.unwrap_unchecked(), self.append_rules); Ok(Self { rules: rules.into(), ..Default::default() }) } }