diff options
author | qkzk <qu3nt1n@gmail.com> | 2022-12-07 23:13:13 +0100 |
---|---|---|
committer | qkzk <qu3nt1n@gmail.com> | 2022-12-07 23:13:13 +0100 |
commit | 911246b8a80f73d98fd5377554eff2d3acce3e5b (patch) | |
tree | 4ca8af1cf88ca624a3cc677c3dbfc2e9a4b5cf80 /src/opener.rs | |
parent | 5b6301bc6a38f6fd3fc2b8e33505f9fc3e8407e8 (diff) |
opener fallback to xdg-open if opener doesn't exist in path
Diffstat (limited to 'src/opener.rs')
-rw-r--r-- | src/opener.rs | 73 |
1 files changed, 54 insertions, 19 deletions
diff --git a/src/opener.rs b/src/opener.rs index e42aeef..03f5240 100644 --- a/src/opener.rs +++ b/src/opener.rs @@ -1,5 +1,7 @@ use std::collections::HashMap; +use std::env; use std::error::Error; +use std::path::{Path, PathBuf}; use std::process::Command; use log::info; @@ -7,7 +9,23 @@ use serde_yaml; use crate::fm_error::{FmError, FmResult}; -#[derive(Clone, Hash, Eq, PartialEq)] +fn find_it<P>(exe_name: P) -> Option<PathBuf> +where + P: AsRef<Path>, +{ + env::var_os("PATH").and_then(|paths| { + env::split_paths(&paths).find_map(|dir| { + let full_path = dir.join(&exe_name); + if full_path.is_file() { + Some(full_path) + } else { + None + } + }) + }) +} + +#[derive(Clone, Hash, Eq, PartialEq, Debug)] pub enum ExtensionKind { Audio, Bitmap, @@ -73,33 +91,44 @@ impl OpenerAssociation { } macro_rules! open_file_with { - ($self:ident, $key:ident, $variant:ident, $yaml:ident) => { - if let Some($key) = OpenerInfo::from_yaml(&$yaml["$key"]) { + ($self:ident, $key:expr, $variant:ident, $yaml:ident) => { + if let Some(o) = OpenerInfo::from_yaml(&$yaml[$key]) { + info!("key {:?} variant {:?}", $key, ExtensionKind::$variant); $self .association .entry(ExtensionKind::$variant) - .and_modify(|e| *e = $key); + .and_modify(|e| *e = o); } }; } + impl OpenerAssociation { fn opener_info(&self, ext: &str) -> Option<&OpenerInfo> { self.association.get(&ExtensionKind::parse(ext)) } fn update_from_file(&mut self, yaml: &serde_yaml::value::Value) { - open_file_with!(self, audio, Audio, yaml); - open_file_with!(self, bitmap_image, Bitmap, yaml); - open_file_with!(self, libreoffice, Office, yaml); - open_file_with!(self, readable, Readable, yaml); - open_file_with!(self, text, Text, yaml); - open_file_with!(self, unknown, Unknown, yaml); - open_file_with!(self, vectorial_image, Vectorial, yaml); - open_file_with!(self, video, Video, yaml); + open_file_with!(self, "audio", Audio, yaml); + open_file_with!(self, "bitmap_image", Bitmap, yaml); + open_file_with!(self, "libreoffice", Office, yaml); + open_file_with!(self, "readable", Readable, yaml); + open_file_with!(self, "text", Text, yaml); + open_file_with!(self, "unknown", Unknown, yaml); + open_file_with!(self, "vectorial_image", Vectorial, yaml); + open_file_with!(self, "video", Video, yaml); + + info!("{:?}", self.association); + + self.validate_openers(); + } + + fn validate_openers(&mut self) { + self.association + .retain(|_, opener| find_it(opener.opener.clone()).is_some()) } } -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct OpenerInfo { opener: String, use_term: bool, @@ -125,6 +154,7 @@ impl OpenerInfo { pub struct Opener { terminal: String, pub opener_association: OpenerAssociation, + default_opener: OpenerInfo, } impl Opener { @@ -132,6 +162,15 @@ impl Opener { Self { terminal, opener_association: OpenerAssociation::new(), + default_opener: OpenerInfo::new("xdg-open", false), + } + } + + fn get_opener(&self, extension: &str) -> &OpenerInfo { + if let Some(opener) = self.opener_association.opener_info(extension) { + opener + } else { + &self.default_opener } } @@ -147,12 +186,7 @@ impl Opener { let extension = extension_os_string .to_str() .ok_or_else(|| FmError::new("Extension couldn't be parsed correctly"))?; - self.open_with( - self.opener_association - .opener_info(extension) - .ok_or_else(|| FmError::new("This extension has no known opener"))?, - filepath, - ) + self.open_with(self.get_opener(extension), filepath) } pub fn open_with( @@ -204,6 +238,7 @@ pub fn load_opener(path: &str, terminal: String) -> Result<Opener, Box<dyn Error let mut opener = Opener::new(terminal); let file = std::fs::File::open(std::path::Path::new(&shellexpand::tilde(path).to_string()))?; let yaml = serde_yaml::from_reader(file)?; + info!("yaml opener : {:?}", yaml); opener.update_from_file(&yaml); Ok(opener) } |