From d33ada281ec39c4f365ec01be7fcd2ed90913cdf Mon Sep 17 00:00:00 2001 From: Piotr <114903054+elevenhsoft@users.noreply.github.com> Date: Wed, 11 Sep 2024 19:33:40 +0200 Subject: [PATCH 1/3] open multiple files in one app instance if possible --- src/app.rs | 51 ++++++++++++++++++++++++++++++++++++++++++++++--- src/mime_app.rs | 12 ++++++++---- src/tab.rs | 15 ++++++++++++++- 3 files changed, 70 insertions(+), 8 deletions(-) diff --git a/src/app.rs b/src/app.rs index 81f1c176..7251b31d 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1677,7 +1677,7 @@ impl Application for App { } } for path in paths { - if let Some(mut command) = terminal.command(None) { + if let Some(mut command) = terminal.command(Vec::new()) { command.current_dir(&path); match spawn_detached(&mut command) { Ok(()) => {} @@ -1697,7 +1697,7 @@ impl Application for App { } } Message::OpenWith(path, app) => { - if let Some(mut command) = app.command(Some(path.clone())) { + if let Some(mut command) = app.command(vec![Some(path.clone())]) { match spawn_detached(&mut command) { Ok(()) => { let _ = recently_used_xbel::update_recently_used( @@ -2119,7 +2119,7 @@ impl Application for App { Ok(entry) => { match entry.section("Desktop Entry").attr("Exec") { Some(exec) => { - match mime_app::exec_to_command(exec, None) { + match mime_app::exec_to_command(exec, Vec::new()) { Some(mut command) => { match spawn_detached(&mut command) { Ok(()) => { @@ -2165,6 +2165,51 @@ impl Application for App { } } } + tab::Command::OpenMultipleFiles(items) => { + let mut groups: HashMap< + String, + Vec<(mime_app::MimeApp, Option)>, + > = HashMap::new(); + + for item in items { + item.open_with + .into_iter() + .filter(|mime| mime.is_default) + .for_each(|app| { + groups + .entry(app.id.clone()) + .or_default() + .push((app, item.path_opt.clone())); + }) + } + + for (_id, values) in groups { + let mut paths = Vec::new(); + let mut mime_app: Option = None; + + for (app, path_opt) in values { + paths.push(path_opt); + mime_app = Some(app); + } + + if let Some(app) = mime_app { + if let Some(mut command) = app.command(paths) { + match spawn_detached(&mut command) { + Ok(()) => {} + Err(err) => { + log::warn!( + "failed to open with {:?}: {}", + app.id, + err + ) + } + } + } else { + log::warn!("failed to get command for {:?}", app.id); + } + } + } + } tab::Command::OpenInNewTab(path) => { commands.push(self.open_tab(Location::Path(path.clone()), false, None)); } diff --git a/src/mime_app.rs b/src/mime_app.rs index 268152fb..f9fdb203 100644 --- a/src/mime_app.rs +++ b/src/mime_app.rs @@ -10,7 +10,7 @@ use std::{ cmp::Ordering, collections::HashMap, env, path::PathBuf, process, sync::Mutex, time::Instant, }; -pub fn exec_to_command(exec: &str, path_opt: Option) -> Option { +pub fn exec_to_command(exec: &str, path_opt: Vec>) -> Option { let args_vec: Vec = shlex::split(exec)?; let mut args = args_vec.iter(); let mut command = process::Command::new(args.next()?); @@ -18,8 +18,12 @@ pub fn exec_to_command(exec: &str, path_opt: Option) -> Option { - if let Some(path) = &path_opt { - command.arg(path); + if !path_opt.is_empty() { + path_opt.iter().for_each(|path| { + if let Some(path) = &path { + command.arg(path); + } + }) } } _ => { @@ -46,7 +50,7 @@ pub struct MimeApp { impl MimeApp { //TODO: move to libcosmic, support multiple files - pub fn command(&self, path_opt: Option) -> Option { + pub fn command(&self, path_opt: Vec>) -> Option { exec_to_command(self.exec.as_deref()?, path_opt) } } diff --git a/src/tab.rs b/src/tab.rs index a20a4cbb..48c16454 100644 --- a/src/tab.rs +++ b/src/tab.rs @@ -764,6 +764,7 @@ pub enum Command { LocationProperties(usize), MoveToTrash(Vec), OpenFile(PathBuf), + OpenMultipleFiles(Vec), OpenInNewTab(PathBuf), OpenInNewWindow(PathBuf), } @@ -1949,21 +1950,33 @@ impl Tab { } } Message::Open => { + let mut many_items = Vec::new(); + if let Some(ref mut items) = self.items_opt { + let selections = items.iter().filter(|item| item.selected).count(); + for item in items.iter() { if item.selected { if let Some(path) = &item.path_opt { if path.is_dir() { //TODO: allow opening multiple tabs? cd = Some(Location::Path(path.clone())); - } else { + } else if selections == 1 { commands.push(Command::OpenFile(path.clone())); } } else { //TODO: open properties? } + + if selections > 1 { + many_items.push(item.clone()); + } } } + + if !many_items.is_empty() { + commands.push(Command::OpenMultipleFiles(many_items)); + } } } Message::RightClick(click_i_opt) => { From 98b2f0f3d5076803ca3a7fe1e5446091058540fa Mon Sep 17 00:00:00 2001 From: Piotr <114903054+elevenhsoft@users.noreply.github.com> Date: Thu, 12 Sep 2024 18:41:40 +0200 Subject: [PATCH 2/3] add fixes for PR --- src/mime_app.rs | 9 ++++++++- src/tab.rs | 6 ++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/mime_app.rs b/src/mime_app.rs index f9fdb203..4f82bb32 100644 --- a/src/mime_app.rs +++ b/src/mime_app.rs @@ -17,7 +17,14 @@ pub fn exec_to_command(exec: &str, path_opt: Vec>) -> Option { + "%f" | "%u" => { + if !path_opt.is_empty() { + if let Some(Some(path)) = &path_opt.first() { + command.arg(path); + } + } + } + "%F" | "%U" => { if !path_opt.is_empty() { path_opt.iter().for_each(|path| { if let Some(path) = &path { diff --git a/src/tab.rs b/src/tab.rs index 5821c733..5f51f4eb 100644 --- a/src/tab.rs +++ b/src/tab.rs @@ -1957,19 +1957,21 @@ impl Tab { let selections = items.iter().filter(|item| item.selected).count(); for item in items.iter() { + let has_default_app = item.open_with.iter().any(|&x| x.is_default); + if item.selected { if let Some(path) = &item.path_opt { if path.is_dir() { //TODO: allow opening multiple tabs? cd = Some(Location::Path(path.clone())); - } else if selections == 1 { + } else if selections == 1 || !has_default_app { commands.push(Command::OpenFile(path.clone())); } } else { //TODO: open properties? } - if selections > 1 { + if selections > 1 && has_default_app { many_items.push(item.clone()); } } From d84703c8421eebfd2e6e3862d68b65b086d0b2ec Mon Sep 17 00:00:00 2001 From: Piotr <114903054+elevenhsoft@users.noreply.github.com> Date: Thu, 12 Sep 2024 18:47:08 +0200 Subject: [PATCH 3/3] fix: remove reference --- src/tab.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tab.rs b/src/tab.rs index 5f51f4eb..ce3259ad 100644 --- a/src/tab.rs +++ b/src/tab.rs @@ -1957,7 +1957,7 @@ impl Tab { let selections = items.iter().filter(|item| item.selected).count(); for item in items.iter() { - let has_default_app = item.open_with.iter().any(|&x| x.is_default); + let has_default_app = item.open_with.iter().any(|x| x.is_default); if item.selected { if let Some(path) = &item.path_opt {