diff --git a/src/config.rs b/src/config.rs index 35058c2..d1f6d4f 100644 --- a/src/config.rs +++ b/src/config.rs @@ -237,6 +237,7 @@ pub struct TunableValues { pub typing_notice_display: bool, pub users: UserOverrides, pub default_room: Option, + pub open_command: Option>, } #[derive(Clone, Default, Deserialize)] @@ -251,6 +252,7 @@ pub struct Tunables { pub typing_notice_display: Option, pub users: Option, pub default_room: Option, + pub open_command: Option>, } impl Tunables { @@ -268,6 +270,7 @@ impl Tunables { typing_notice_display: self.typing_notice_display.or(other.typing_notice_display), users: merge_users(self.users, other.users), default_room: self.default_room.or(other.default_room), + open_command: self.open_command.or(other.open_command), } } @@ -283,6 +286,7 @@ impl Tunables { typing_notice_display: self.typing_notice_display.unwrap_or(true), users: self.users.unwrap_or_default(), default_room: self.default_room, + open_command: self.open_command, } } } diff --git a/src/tests.rs b/src/tests.rs index 322556e..ce9014c 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -188,6 +188,7 @@ pub fn mock_tunables() -> TunableValues { })] .into_iter() .collect::>(), + open_command: None, } } diff --git a/src/windows/room/chat.rs b/src/windows/room/chat.rs index 2808310..4cba31b 100644 --- a/src/windows/room/chat.rs +++ b/src/windows/room/chat.rs @@ -1,10 +1,11 @@ use std::borrow::Cow; -use std::ffi::OsStr; +use std::ffi::{OsStr, OsString}; use std::fs; use std::ops::Deref; use std::path::{Path, PathBuf}; use modalkit::editing::store::RegisterError; +use std::process::Command; use tokio; use matrix_sdk::{ @@ -246,14 +247,21 @@ impl ChatState { } let info = if flags.contains(DownloadFlags::OPEN) { - // open::that may not return until the spawned program closes. let target = filename.clone().into_os_string(); - tokio::task::spawn_blocking(move || open::that(target)); - - InfoMessage::from(format!( - "Attachment downloaded to {} and opened", - filename.display() - )) + match open_command( + store.application.settings.tunables.open_command.as_ref(), + target, + ) { + Ok(_) => { + InfoMessage::from(format!( + "Attachment downloaded to {} and opened", + filename.display() + )) + }, + Err(err) => { + return Err(err); + }, + } } else { InfoMessage::from(format!( "Attachment downloaded to {}", @@ -844,3 +852,26 @@ impl<'a> StatefulWidget for Chat<'a> { scrollback.render(scrollarea, buf, &mut state.scrollback); } } + +fn open_command(open_command: Option<&Vec>, target: OsString) -> IambResult<()> { + if let Some(mut cmd) = open_command.and_then(cmd) { + cmd.arg(target); + cmd.spawn()?; + return Ok(()); + } else { + // open::that may not return until the spawned program closes. + tokio::task::spawn_blocking(move || { + return open::that(target); + }); + return Ok(()); + } +} + +fn cmd(open_command: &Vec) -> Option { + if let [program, args @ ..] = open_command.as_slice() { + let mut cmd = Command::new(program); + cmd.args(args); + return Some(cmd); + } + None +}