diff --git a/Cargo.lock b/Cargo.lock index a7b5075..c04a640 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -244,6 +244,17 @@ version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4eb2cdb97421e01129ccb49169d8279ed21e829929144f4a22a6e54ac549ca1" +[[package]] +name = "async-trait" +version = "0.1.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + [[package]] name = "atomic-waker" version = "1.1.2" @@ -428,6 +439,7 @@ version = "0.6.0" dependencies = [ "anyhow", "async-std", + "async-trait", "battery", "chrono", "freedesktop-desktop-entry", diff --git a/client/Cargo.toml b/client/Cargo.toml index dd62f6c..c770f2b 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -14,15 +14,16 @@ anyhow = { version = "1.0.75", features = ["backtrace"] } # application window iced = { version = "0.10.0", features = ["svg"] } -# search +# plugins fuzzy-matcher = "0.3.7" +async-trait = "0.1.74" +async-std = "1.12.0" # reading index files serde = "1.0.188" serde_json = "1.0.94" # clock plugin -async-std = "1.12.0" chrono = "0.4.26" # applications plugin diff --git a/client/src/main.rs b/client/src/main.rs index 43e104f..1088d0b 100644 --- a/client/src/main.rs +++ b/client/src/main.rs @@ -117,13 +117,19 @@ impl Application for Centerpiece { } _ => None, }), - crate::plugin::windows::Plugin::spawn(), - crate::plugin::applications::Plugin::spawn(), - crate::plugin::brave::progressive_web_apps::Plugin::spawn(), - crate::plugin::git_repositories::Plugin::spawn(), - crate::plugin::brave::bookmarks::Plugin::spawn(), - crate::plugin::resource_monitor::Plugin::spawn(), - crate::plugin::clock::Plugin::spawn(), + crate::plugin::utils::spawn::(), + crate::plugin::utils::spawn::(), + crate::plugin::utils::spawn::< + crate::plugin::brave::progressive_web_apps::ProgressiveWebAppsPlugin, + >(), + crate::plugin::utils::spawn::(), + crate::plugin::utils::spawn::(), + crate::plugin::utils::spawn::( + ), + crate::plugin::utils::spawn::(), + crate::plugin::utils::spawn::(), + crate::plugin::utils::spawn::(), + crate::plugin::utils::spawn::(), ]); } diff --git a/client/src/plugin/applications.rs b/client/src/plugin/applications.rs index 1300e80..dad2e5c 100644 --- a/client/src/plugin/applications.rs +++ b/client/src/plugin/applications.rs @@ -1,11 +1,8 @@ +use crate::plugin::utils::Plugin; use anyhow::Context; -use iced::futures::StreamExt; -pub struct Plugin { - plugin: crate::model::Plugin, - all_entries: Vec, - plugin_channel_out: iced::futures::channel::mpsc::Sender, - plugin_channel_in: iced::futures::channel::mpsc::Receiver, +pub struct ApplicationsPlugin { + entries: Vec, } #[derive(Debug, Clone)] @@ -123,38 +120,34 @@ impl ExtendedEntry { } } -impl Plugin { - pub fn spawn() -> iced::Subscription { - return iced::subscription::channel( - std::any::TypeId::of::(), - 100, - |plugin_channel_out| async { - let mut plugin = Plugin::new(plugin_channel_out); - plugin.main().await - }, - ); +impl Plugin for ApplicationsPlugin { + fn new() -> Self { + return Self { entries: vec![] }; } - pub fn new( - plugin_channel_out: iced::futures::channel::mpsc::Sender, - ) -> Plugin { - let (app_channel_out, plugin_channel_in) = iced::futures::channel::mpsc::channel(100); - - return Plugin { - all_entries: Plugin::all_entries(), - plugin_channel_in, - plugin_channel_out, - plugin: crate::model::Plugin { - id: String::from("applications"), - priority: 29, - title: String::from("󰀻 Apps"), - app_channel_out, - entries: vec![], - }, - }; + fn id() -> &'static str { + return "applications"; + } + + fn priority() -> u32 { + return 29; + } + + fn title() -> &'static str { + return "󰀻 Apps"; + } + + fn entries(&self) -> Vec { + return self + .entries + .iter() + .map(|extended_entry| extended_entry.entry.clone()) + .collect(); } - fn all_entries() -> Vec { + fn update_entries(&mut self) -> anyhow::Result<()> { + self.entries.clear(); + let paths = freedesktop_desktop_entry::Iter::new(freedesktop_desktop_entry::default_paths()); let desktop_entries: std::collections::HashSet = paths @@ -167,83 +160,18 @@ impl Plugin { return desktop_entry_result.ok(); }) .collect(); - return desktop_entries.into_iter().collect(); - } - - async fn main(&mut self) -> ! { - let register_plugin_result = self.register_plugin(); - if let Err(error) = register_plugin_result { - log::error!( - target: self.plugin.id.as_str(), - "{:?}", error - ); - panic!(); - } - - let search_result = self.search(&String::from("")); - if let Err(error) = search_result { - log::warn!( - target: self.plugin.id.as_str(), - "{:?}", error - ); - } - - loop { - let update_result = self.update().await; - if let Err(error) = update_result { - log::warn!( - target: self.plugin.id.as_str(), - "{:?}", error - ); - } - } - } - - fn register_plugin(&mut self) -> anyhow::Result<()> { - self.plugin_channel_out - .try_send(crate::Message::RegisterPlugin(self.plugin.clone())) - .context("Failed to send message to register plugin.")?; - - return Ok(()); - } - - async fn update(&mut self) -> anyhow::Result<()> { - let plugin_request = self.plugin_channel_in.select_next_some().await; - - match plugin_request { - crate::model::PluginRequest::Search(query) => self.search(&query)?, - crate::model::PluginRequest::Timeout => (), - crate::model::PluginRequest::Activate(entry_id) => self.activate(entry_id)?, - } - - return Ok(()); - } - - fn search(&mut self, query: &String) -> anyhow::Result<()> { - let all_entries = self - .all_entries - .clone() - .into_iter() - .map(|extended_entry| extended_entry.entry) - .collect(); - let filtered_entries = crate::plugin::utils::search(all_entries, query); - - self.plugin_channel_out - .try_send(crate::Message::UpdateEntries( - self.plugin.id.clone(), - filtered_entries, - )) - .context(format!( - "Failed to send message to update entries while searching for '{}'.", - query - ))?; + self.entries = desktop_entries.into_iter().collect(); return Ok(()); } - fn activate(&mut self, entry_id: String) -> anyhow::Result<()> { + fn activate( + &mut self, + entry_id: String, + plugin_channel_out: &mut iced::futures::channel::mpsc::Sender, + ) -> anyhow::Result<()> { let entry = self - .all_entries + .entries .iter() .find(|e| e.entry.id == entry_id) .context(format!( @@ -261,7 +189,7 @@ impl Plugin { entry_id ))?; - self.plugin_channel_out + plugin_channel_out .try_send(crate::Message::Exit) .context(format!( "Failed to send message to exit application while activating entry with id '{}'.", diff --git a/client/src/plugin/brave/bookmarks.rs b/client/src/plugin/brave/bookmarks.rs index 19f05a5..ee483ac 100644 --- a/client/src/plugin/brave/bookmarks.rs +++ b/client/src/plugin/brave/bookmarks.rs @@ -1,120 +1,47 @@ +use crate::plugin::utils::Plugin; use anyhow::Context; -use iced::futures::StreamExt; -pub struct Plugin { - plugin: crate::model::Plugin, - plugin_channel_out: iced::futures::channel::mpsc::Sender, - plugin_channel_in: iced::futures::channel::mpsc::Receiver, +pub struct BookmarksPlugin { + entries: Vec, } -impl Plugin { - pub fn spawn() -> iced::Subscription { - return iced::subscription::channel( - std::any::TypeId::of::(), - 100, - |plugin_channel_out| async { - let mut plugin = Plugin::new(plugin_channel_out); - plugin.main().await - }, - ); +impl Plugin for BookmarksPlugin { + fn id() -> &'static str { + return "brave-bookmarks"; } - pub fn new(plugin_channel_out: iced::futures::channel::mpsc::Sender) -> Plugin { - let (app_channel_out, plugin_channel_in) = iced::futures::channel::mpsc::channel(100); + fn priority() -> u32 { + return 25; + } - let pwa_entries_result = Plugin::all_entries(); - if let Err(error) = pwa_entries_result { - log::error!( - target: "brave-bookmarks", - "{:?}", error - ); - // TODO: process exit terminates the parent process as well! This is unwanted - panic!(); - } + fn title() -> &'static str { + return "󰃃 Bookmarks"; + } - return Plugin { - plugin_channel_in, - plugin_channel_out, - plugin: crate::model::Plugin { - id: String::from("brave-bookmarks"), - priority: 25, - title: String::from("󰃃 Bookmarks"), - app_channel_out, - entries: pwa_entries_result.unwrap(), - }, - }; + fn entries(&self) -> Vec { + return self.entries.clone(); } - fn all_entries() -> anyhow::Result> { - let bookmarks_root: crate::plugin::brave::utils::Bookmark = - crate::plugin::brave::utils::read_bookmarks_file()?; + fn new() -> Self { + return Self { entries: vec![] }; + } - let bookmarks = bookmarks_root + fn update_entries(&mut self) -> anyhow::Result<()> { + self.entries.clear(); + self.entries = crate::plugin::brave::utils::read_bookmarks_file()? .get_bookmarks_recursive(&vec![String::from("Progressive Web Apps")]) .into_iter() .map(|bookmark| bookmark.into()) .collect(); - return Ok(bookmarks); - } - - async fn main(&mut self) -> ! { - let register_plugin_result = self.register_plugin(); - if let Err(error) = register_plugin_result { - log::error!( - target: self.plugin.id.as_str(), - "{:?}", error, - ); - panic!(); - } - - loop { - let update_result = self.update().await; - if let Err(error) = update_result { - log::warn!( - target: self.plugin.id.as_str(), - "{:?}", error, - ); - } - } - } - - fn register_plugin(&mut self) -> anyhow::Result<()> { - self.plugin_channel_out - .try_send(crate::Message::RegisterPlugin(self.plugin.clone())) - .context("Failed to send message to register plugin.")?; - return Ok(()); - } - - async fn update(&mut self) -> anyhow::Result<()> { - let plugin_request = self.plugin_channel_in.select_next_some().await; - - match plugin_request { - crate::model::PluginRequest::Search(query) => self.search(&query)?, - crate::model::PluginRequest::Timeout => (), - crate::model::PluginRequest::Activate(entry_id) => self.activate(entry_id)?, - } - - return Ok(()); - } - - fn search(&mut self, query: &String) -> anyhow::Result<()> { - let filtered_entries = crate::plugin::utils::search(self.plugin.entries.clone(), query); - - self.plugin_channel_out - .try_send(crate::Message::UpdateEntries( - self.plugin.id.clone(), - filtered_entries, - )) - .context(format!( - "Failed to send message to update entries while searching for '{}'.", - query - ))?; - return Ok(()); } - fn activate(&mut self, entry_id: String) -> anyhow::Result<()> { + fn activate( + &mut self, + entry_id: String, + plugin_channel_out: &mut iced::futures::channel::mpsc::Sender, + ) -> anyhow::Result<()> { std::process::Command::new("brave") .arg(&entry_id) .spawn() @@ -123,7 +50,7 @@ impl Plugin { entry_id ))?; - self.plugin_channel_out + plugin_channel_out .try_send(crate::Message::Exit) .context(format!( "Failed to send message to exit application while activating entry with id '{}'.", diff --git a/client/src/plugin/brave/progressive_web_apps.rs b/client/src/plugin/brave/progressive_web_apps.rs index 03cd94f..6ed89b6 100644 --- a/client/src/plugin/brave/progressive_web_apps.rs +++ b/client/src/plugin/brave/progressive_web_apps.rs @@ -1,127 +1,56 @@ +use crate::plugin::utils::Plugin; use anyhow::Context; -use iced::futures::StreamExt; -pub struct Plugin { - plugin: crate::model::Plugin, - plugin_channel_out: iced::futures::channel::mpsc::Sender, - plugin_channel_in: iced::futures::channel::mpsc::Receiver, +pub struct ProgressiveWebAppsPlugin { + entries: Vec, } -impl Plugin { - pub fn spawn() -> iced::Subscription { - return iced::subscription::channel( - std::any::TypeId::of::(), - 100, - |plugin_channel_out| async { - let mut plugin = Plugin::new(plugin_channel_out); - plugin.main().await - }, - ); +impl Plugin for ProgressiveWebAppsPlugin { + fn id() -> &'static str { + return "brave-progressive-web-apps"; } - pub fn new(plugin_channel_out: iced::futures::channel::mpsc::Sender) -> Plugin { - let (app_channel_out, plugin_channel_in) = iced::futures::channel::mpsc::channel(100); + fn priority() -> u32 { + return 28; + } + + fn title() -> &'static str { + return "󰀻 Progressive Web Apps"; + } - let pwa_entries_result = Plugin::all_entries(); - if let Err(error) = pwa_entries_result { - log::error!( - target: "brave-progressive-web-apps", - "{:?}", error - ); - panic!(); - } + fn entries(&self) -> Vec { + return self.entries.clone(); + } - return Plugin { - plugin_channel_in, - plugin_channel_out, - plugin: crate::model::Plugin { - id: String::from("brave-progressive-web-apps"), - priority: 28, - title: String::from("󰀻 Progressive Web Apps"), - app_channel_out, - entries: pwa_entries_result.unwrap(), - }, - }; + fn new() -> Self { + return Self { entries: vec![] }; } - fn all_entries() -> anyhow::Result> { - let bookmarks_root: crate::plugin::brave::utils::Bookmark = - crate::plugin::brave::utils::read_bookmarks_file()?; + fn update_entries(&mut self) -> anyhow::Result<()> { + self.entries.clear(); let folder_name = String::from("Progressive Web Apps"); + let bookmarks_root = crate::plugin::brave::utils::read_bookmarks_file()?; let pwa_folder = bookmarks_root .find_bookmarks_folder_recursive(&folder_name) .ok_or(anyhow::anyhow!( "Unable to find a bookmarks folder named '{}'.", folder_name ))?; - - let pwa_bookmarks = pwa_folder + self.entries = pwa_folder .get_bookmarks_recursive(&vec![]) .into_iter() .map(|bookmark| bookmark.into()) .collect(); - return Ok(pwa_bookmarks); - } - - async fn main(&mut self) -> ! { - let register_plugin_result = self.register_plugin(); - if let Err(error) = register_plugin_result { - log::error!( - target: self.plugin.id.as_str(), - "{:?}", error, - ); - panic!(); - } - - loop { - let update_result = self.update().await; - if let Err(error) = update_result { - log::warn!( - target: self.plugin.id.as_str(), - "{:?}", error, - ); - } - } - } - - fn register_plugin(&mut self) -> anyhow::Result<()> { - self.plugin_channel_out - .try_send(crate::Message::RegisterPlugin(self.plugin.clone())) - .context("Failed to send message to register plugin.")?; - return Ok(()); - } - - async fn update(&mut self) -> anyhow::Result<()> { - let plugin_request = self.plugin_channel_in.select_next_some().await; - - match plugin_request { - crate::model::PluginRequest::Search(query) => self.search(&query)?, - crate::model::PluginRequest::Timeout => (), - crate::model::PluginRequest::Activate(entry_id) => self.activate(entry_id)?, - } - - return Ok(()); - } - - fn search(&mut self, query: &String) -> anyhow::Result<()> { - let filtered_entries = crate::plugin::utils::search(self.plugin.entries.clone(), query); - - self.plugin_channel_out - .try_send(crate::Message::UpdateEntries( - self.plugin.id.clone(), - filtered_entries, - )) - .context(format!( - "Failed to send message to update entries while searching for '{}'.", - query - ))?; - return Ok(()); } - fn activate(&mut self, entry_id: String) -> anyhow::Result<()> { + fn activate( + &mut self, + entry_id: String, + plugin_channel_out: &mut iced::futures::channel::mpsc::Sender, + ) -> anyhow::Result<()> { std::process::Command::new("brave") .arg(format!("--app={}", entry_id)) .spawn() @@ -130,7 +59,7 @@ impl Plugin { entry_id ))?; - self.plugin_channel_out + plugin_channel_out .try_send(crate::Message::Exit) .context(format!( "Failed to send message to exit application while activating entry with id '{}'.", diff --git a/client/src/plugin/clock.rs b/client/src/plugin/clock.rs index 8ae6e43..a4b1f53 100644 --- a/client/src/plugin/clock.rs +++ b/client/src/plugin/clock.rs @@ -1,47 +1,35 @@ -use anyhow::Context; -use iced::futures::StreamExt; +use crate::plugin::utils::Plugin; -pub struct Plugin { - plugin: crate::model::Plugin, - last_query: String, - plugin_channel_out: iced::futures::channel::mpsc::Sender, - plugin_channel_in: iced::futures::channel::mpsc::Receiver, +pub struct ClockPlugin { + entries: Vec, } -impl Plugin { - pub fn spawn() -> iced::Subscription { - return iced::subscription::channel( - std::any::TypeId::of::(), - 100, - |plugin_channel_out| async { - let mut plugin = Plugin::new(plugin_channel_out); - plugin.main().await - }, - ); +impl Plugin for ClockPlugin { + fn new() -> Self { + return Self { entries: vec![] }; } - pub fn new( - plugin_channel_out: iced::futures::channel::mpsc::Sender, - ) -> Plugin { - let (app_channel_out, plugin_channel_in) = iced::futures::channel::mpsc::channel(100); + fn id() -> &'static str { + return "clock"; + } - return Plugin { - last_query: String::new(), - plugin_channel_in, - plugin_channel_out, - plugin: crate::model::Plugin { - id: String::from("clock"), - priority: 10, - title: String::from("󰅐 Clock"), - app_channel_out, - entries: Plugin::all_entries(), - }, - }; + fn priority() -> u32 { + return 10; } - fn all_entries() -> Vec { + fn title() -> &'static str { + return "󰅐 Clock"; + } + + fn update_timeout() -> Option { + return Some(std::time::Duration::from_secs(1)); + } + + fn update_entries(&mut self) -> anyhow::Result<()> { + self.entries.clear(); + let date = chrono::Local::now(); - return vec![ + self.entries = vec![ crate::model::Entry { id: String::from("time-entry"), title: date.format("%H:%M:%S").to_string(), @@ -55,71 +43,11 @@ impl Plugin { meta: String::from("Clock Date"), }, ]; - } - - async fn main(&mut self) -> ! { - let register_plugin_result = self.register_plugin(); - if let Err(error) = register_plugin_result { - log::error!( - target: self.plugin.id.as_str(), - "{:?}", error - ); - panic!(); - } - - loop { - let update_result = self.update().await; - if let Err(error) = update_result { - log::warn!( - target: self.plugin.id.as_str(), - "{:?}", error - ); - } - } - } - - fn register_plugin(&mut self) -> anyhow::Result<()> { - self.plugin_channel_out - .try_send(crate::Message::RegisterPlugin(self.plugin.clone())) - .context("Failed to send message to register plugin.")?; return Ok(()); } - async fn update(&mut self) -> anyhow::Result<()> { - let plugin_request_future = self.plugin_channel_in.select_next_some(); - let plugin_request = - async_std::future::timeout(std::time::Duration::from_secs(1), plugin_request_future) - .await - .unwrap_or(crate::model::PluginRequest::Timeout); - - match plugin_request { - crate::model::PluginRequest::Search(query) => self.search(query)?, - crate::model::PluginRequest::Timeout => { - self.plugin.entries = Plugin::all_entries(); - self.search(self.last_query.clone())?; - } - crate::model::PluginRequest::Activate(_) => (), - } - - return Ok(()); - } - - fn search(&mut self, query: String) -> anyhow::Result<()> { - let filtered_entries = crate::plugin::utils::search(self.plugin.entries.clone(), &query); - - self.plugin_channel_out - .try_send(crate::Message::UpdateEntries( - self.plugin.id.clone(), - filtered_entries, - )) - .context(format!( - "Failed to send message to update entries while searching for '{}'.", - query - ))?; - - self.last_query = query; - - return Ok(()); + fn entries(&self) -> Vec { + return self.entries.clone(); } } diff --git a/client/src/plugin/git_repositories.rs b/client/src/plugin/git_repositories.rs index 0e676c5..7ae9a80 100644 --- a/client/src/plugin/git_repositories.rs +++ b/client/src/plugin/git_repositories.rs @@ -1,49 +1,40 @@ +use crate::plugin::utils::Plugin; use anyhow::Context; -use iced::futures::StreamExt; -pub struct Plugin { - plugin: crate::model::Plugin, - plugin_channel_out: iced::futures::channel::mpsc::Sender, - plugin_channel_in: iced::futures::channel::mpsc::Receiver, +pub struct GitRepositoriesPlugin { + entries: Vec, } -impl Plugin { - pub fn spawn() -> iced::Subscription { - return iced::subscription::channel( - std::any::TypeId::of::(), - 100, - |plugin_channel_out| async { - let mut plugin = Plugin::new(plugin_channel_out); - plugin.main().await - }, - ); +impl Plugin for GitRepositoriesPlugin { + fn id() -> &'static str { + return "git-repositories"; } - pub fn new( - plugin_channel_out: iced::futures::channel::mpsc::Sender, - ) -> Plugin { - let (app_channel_out, plugin_channel_in) = iced::futures::channel::mpsc::channel(100); - - return Plugin { - plugin_channel_in, - plugin_channel_out, - plugin: crate::model::Plugin { - id: String::from("git-repositories"), - priority: 28, - title: String::from("󰘬 Git Repositories"), - app_channel_out, - entries: Plugin::all_entries(), - }, - }; + fn priority() -> u32 { + return 28; } - fn all_entries() -> Vec { + fn title() -> &'static str { + return "󰘬 Git Repositories"; + } + + fn entries(&self) -> Vec { + return self.entries.clone(); + } + + fn new() -> Self { + return Self { entries: vec![] }; + } + + fn update_entries(&mut self) -> anyhow::Result<()> { + self.entries.clear(); + let git_repository_paths: Vec = crate::plugin::utils::read_index_file("git-repositories-index.json"); let home = std::env::var("HOME").unwrap_or(String::from("")); - return git_repository_paths + self.entries = git_repository_paths .into_iter() .filter_map(|git_repository_path| { let git_repository_display_name = git_repository_path.replacen(&home, "~", 1); @@ -56,65 +47,15 @@ impl Plugin { }); }) .collect(); - } - - async fn main(&mut self) -> ! { - let register_plugin_result = self.register_plugin(); - if let Err(error) = register_plugin_result { - log::error!( - target: self.plugin.id.as_str(), - "{:?}", error, - ); - panic!(); - } - - loop { - let update_result = self.update().await; - if let Err(error) = update_result { - log::warn!( - target: self.plugin.id.as_str(), - "{:?}", error, - ); - } - } - } - - fn register_plugin(&mut self) -> anyhow::Result<()> { - self.plugin_channel_out - .try_send(crate::Message::RegisterPlugin(self.plugin.clone())) - .context("Failed to send message to register plugin.")?; - return Ok(()); - } - - async fn update(&mut self) -> anyhow::Result<()> { - let plugin_request = self.plugin_channel_in.select_next_some().await; - - match plugin_request { - crate::model::PluginRequest::Search(query) => self.search(&query)?, - crate::model::PluginRequest::Timeout => (), - crate::model::PluginRequest::Activate(entry_id) => self.activate(entry_id)?, - } - - return Ok(()); - } - - fn search(&mut self, query: &String) -> anyhow::Result<()> { - let filtered_entries = crate::plugin::utils::search(self.plugin.entries.clone(), query); - - self.plugin_channel_out - .try_send(crate::Message::UpdateEntries( - self.plugin.id.clone(), - filtered_entries, - )) - .context(format!( - "Failed to send message to update entries while searching for '{}'.", - query - ))?; return Ok(()); } - fn activate(&mut self, entry_id: String) -> anyhow::Result<()> { + fn activate( + &mut self, + entry_id: String, + plugin_channel_out: &mut iced::futures::channel::mpsc::Sender, + ) -> anyhow::Result<()> { std::process::Command::new("alacritty") .arg("--working-directory") .arg(&entry_id) @@ -142,7 +83,7 @@ impl Plugin { entry_id ))?; - self.plugin_channel_out + plugin_channel_out .try_send(crate::Message::Exit) .context(format!( "Failed to send message to exit application while activating entry with id '{}'.", diff --git a/client/src/plugin/resource_monitor.rs b/client/src/plugin/resource_monitor.rs deleted file mode 100644 index 1e4fbef..0000000 --- a/client/src/plugin/resource_monitor.rs +++ /dev/null @@ -1,294 +0,0 @@ -use std::ops::Rem; -use anyhow::Context; -use iced::futures::StreamExt; -use sysinfo::{CpuExt, DiskExt, SystemExt}; - -pub struct Plugin { - sysinfo: sysinfo::System, - battery_plugin: crate::model::Plugin, - cpu_plugin: crate::model::Plugin, - disk_plugin: crate::model::Plugin, - memory_plugin: crate::model::Plugin, - last_query: String, - plugin_channel_out: iced::futures::channel::mpsc::Sender, - plugin_channel_in: iced::futures::channel::mpsc::Receiver, -} - -impl Plugin { - pub fn spawn() -> iced::Subscription { - return iced::subscription::channel( - std::any::TypeId::of::(), - 100, - |plugin_channel_out| async { - let mut plugin = Plugin::new(plugin_channel_out); - plugin.main().await - }, - ); - } - - pub fn new( - plugin_channel_out: iced::futures::channel::mpsc::Sender, - ) -> Plugin { - let (app_channel_out, plugin_channel_in) = iced::futures::channel::mpsc::channel(100); - - return Plugin { - sysinfo: sysinfo::System::new_all(), - last_query: String::new(), - plugin_channel_in, - plugin_channel_out, - battery_plugin: crate::model::Plugin { - id: String::from("battery"), - priority: 14, - title: String::from("󰁼 Battery"), - app_channel_out: app_channel_out.clone(), - entries: vec![], - }, - cpu_plugin: crate::model::Plugin { - id: String::from("cpu-usage"), - priority: 13, - title: String::from("󰍛 CPU"), - app_channel_out: app_channel_out.clone(), - entries: vec![], - }, - disk_plugin: crate::model::Plugin { - id: String::from("disk-usage"), - priority: 12, - title: String::from("󱛟 Disks"), - app_channel_out: app_channel_out.clone(), - entries: vec![], - }, - memory_plugin: crate::model::Plugin { - id: String::from("memory-usage"), - priority: 11, - title: String::from("󱓱 Memory"), - app_channel_out, - entries: vec![], - }, - }; - } - - async fn main(&mut self) -> ! { - let register_plugin_result = self.register_plugins(); - if let Err(error) = register_plugin_result { - log::error!( - target: "resource-monitor", - "{:?}", error, - ); - panic!(); - } - - let update_entries_result = self.update_entries(); - if let Err(error) = update_entries_result { - log::warn!( - target: "resource-monitor", - "{:?}", error, - ); - } - - loop { - let update_result = self.update().await; - if let Err(error) = update_result { - log::warn!( - target: "resource-monitor", - "{:?}", error, - ); - } - } - } - - fn register_plugins(&mut self) -> anyhow::Result<()> { - self.plugin_channel_out - .try_send(crate::Message::RegisterPlugin(self.battery_plugin.clone())) - .context("Failed to send message to register the battery plugin.")?; - - self.plugin_channel_out - .try_send(crate::Message::RegisterPlugin(self.cpu_plugin.clone())) - .context("Failed to send message to register the cpu plugin.")?; - - self.plugin_channel_out - .try_send(crate::Message::RegisterPlugin(self.disk_plugin.clone())) - .context("Failed to send message to register the disk plugin.")?; - - self.plugin_channel_out - .try_send(crate::Message::RegisterPlugin(self.memory_plugin.clone())) - .context("Failed to send message to register the memory plugin.")?; - - return Ok(()); - } - - async fn update(&mut self) -> anyhow::Result<()> { - let plugin_request_future = self.plugin_channel_in.select_next_some(); - let plugin_request = - async_std::future::timeout(std::time::Duration::from_secs(2), plugin_request_future) - .await - .unwrap_or(crate::model::PluginRequest::Timeout); - - match plugin_request { - crate::model::PluginRequest::Search(query) => self.search(query)?, - crate::model::PluginRequest::Timeout => self.update_entries()?, - crate::model::PluginRequest::Activate(_) => (), - } - - return Ok(()); - } - - fn update_entries(&mut self) -> anyhow::Result<()> { - self.sysinfo.refresh_all(); - - self.update_battery_entries()?; - self.update_cpu_entries(); - self.update_disk_entries()?; - self.update_memory_entries(); - - self.search(self.last_query.clone())?; - return Ok(()); - } - - fn update_battery_entries(&mut self) -> anyhow::Result<()> { - self.battery_plugin.entries.clear(); - - let batteries = battery::Manager::new() - .context("Failed to create battery manager.")? - .batteries() - .context("Failed to list batteries using the battery manager.")?; - - for battery_result in batteries { - let battery = - battery_result.context("Failed to get battery using the batteries iterator.")?; - - let state_of_charge = battery.state_of_charge() * 100.0; - - let time_to_full_remaining = match battery.time_to_full() { - Some(time_to_full) => to_display(time_to_full), - None => String::new(), - }; - - let time_to_empty_remaining = match battery.time_to_empty() { - Some(time_to_empty) => to_display(time_to_empty), - None => String::new(), - }; - - let title = format!( - "{state_of_charge:.0?}% – {state}{time_to_full_remaining}{time_to_empty_remaining}", - state = battery.state(), - ); - - self.battery_plugin.entries.push(crate::model::Entry { - id: String::from("battery"), - title, - action: String::from(""), - meta: String::from("Resource Monitor Battery"), - }); - } - - return Ok(()); - } - - fn update_memory_entries(&mut self) { - self.memory_plugin.entries.clear(); - - let perentage_used = 100 * self.sysinfo.used_memory() / self.sysinfo.total_memory(); - let total_memory_in_gb = self.sysinfo.total_memory() as f64 / 10_f64.powf(9.); - let used_memory_in_gb = self.sysinfo.used_memory() as f64 / 10_f64.powf(9.); - - let title = format!( - "{}% ({:.2}gb / {:.2}gb)", - perentage_used, used_memory_in_gb, total_memory_in_gb - ); - - self.memory_plugin.entries.push(crate::model::Entry { - id: String::from("memory"), - title, - action: String::from(""), - meta: String::from("Resource Monitor Memory RAM"), - }); - } - - fn update_disk_entries(&mut self) -> anyhow::Result<()> { - self.disk_plugin.entries.clear(); - - for disk in self.sysinfo.disks() { - let mount_point = disk - .mount_point() - .to_str() - .context("Unable to convert mount point path to string.")? - .to_string(); - - let used_space = disk.total_space() - disk.available_space(); - let perentage_used = 100 * used_space / disk.total_space(); - let total_space_in_gb = disk.total_space() as f64 / 10_f64.powf(9.); - let used_space_in_gb = used_space as f64 / 10_f64.powf(9.); - - let title = format!( - "{} {}% ({:.2}gb / {:.2}gb)", - &mount_point, perentage_used, used_space_in_gb, total_space_in_gb - ); - - self.disk_plugin.entries.push(crate::model::Entry { - id: mount_point, - title, - action: String::from(""), - meta: String::from("Resource Monitor Disks"), - }); - } - - return Ok(()); - } - - fn update_cpu_entries(&mut self) { - self.cpu_plugin.entries.clear(); - - for cpu_core in self.sysinfo.cpus() { - self.cpu_plugin.entries.push(crate::model::Entry { - id: cpu_core.name().to_string(), - title: format!( - "{}: {}% {}MHz", - cpu_core.name(), - cpu_core.cpu_usage() as i32, - cpu_core.frequency() - ), - action: String::from(""), - meta: String::from("Resource Monitor Disks"), - }); - } - } - - fn search(&mut self, query: String) -> anyhow::Result<()> { - for plugin in vec![ - &self.battery_plugin, - &self.cpu_plugin, - &self.disk_plugin, - &self.memory_plugin, - ] { - let filtered_entries = crate::plugin::utils::search(plugin.entries.clone(), &query); - - self.plugin_channel_out - .try_send(crate::Message::UpdateEntries( - plugin.id.clone(), - filtered_entries, - )) - .context(format!( - "Failed to send message to update entries for plugin with id '{}' while searching for '{}'.", - plugin.id, - query - ))?; - } - - self.last_query = query; - return Ok(()); - } -} - -fn to_display(time_to_empty: battery::units::Time) -> String { - let mut formatted_time_remaining = String::from(":"); - let hours = (time_to_empty.value / 60.0 / 60.0).round(); - if hours > 0.0 { - formatted_time_remaining.push_str(format!(" {hours:.0}h").as_str()) - } - let minutes = (time_to_empty.value / 60.0).rem(60.0).round(); - if minutes > 0.0 { - formatted_time_remaining.push_str(format!(" {minutes:.0}m").as_str()) - } - formatted_time_remaining.push_str(" remaining"); - formatted_time_remaining -} diff --git a/client/src/plugin/resource_monitor/battery.rs b/client/src/plugin/resource_monitor/battery.rs new file mode 100644 index 0000000..f35ece9 --- /dev/null +++ b/client/src/plugin/resource_monitor/battery.rs @@ -0,0 +1,87 @@ +use crate::plugin::utils::Plugin; +use anyhow::Context; +use std::ops::Rem; + +pub struct BatteryPlugin { + entries: Vec, +} + +impl Plugin for BatteryPlugin { + fn id() -> &'static str { + return "battery"; + } + + fn priority() -> u32 { + return 14; + } + + fn title() -> &'static str { + return "󰁼 Battery"; + } + + fn update_timeout() -> Option { + return Some(std::time::Duration::from_secs(2)); + } + + fn entries(&self) -> Vec { + return self.entries.clone(); + } + + fn update_entries(&mut self) -> anyhow::Result<()> { + self.entries.clear(); + + let batteries = battery::Manager::new() + .context("Failed to create battery manager.")? + .batteries() + .context("Failed to list batteries using the battery manager.")?; + + for battery_result in batteries { + let battery = + battery_result.context("Failed to get battery using the batteries iterator.")?; + + let state_of_charge = battery.state_of_charge() * 100.0; + + let time_to_full_remaining = match battery.time_to_full() { + Some(time_to_full) => to_display(time_to_full), + None => String::new(), + }; + + let time_to_empty_remaining = match battery.time_to_empty() { + Some(time_to_empty) => to_display(time_to_empty), + None => String::new(), + }; + + let title = format!( + "{state_of_charge:.0?}% – {state}{time_to_full_remaining}{time_to_empty_remaining}", + state = battery.state(), + ); + + self.entries.push(crate::model::Entry { + id: String::from("battery"), + title, + action: String::from(""), + meta: String::from("Resource Monitor Battery"), + }); + } + + return Ok(()); + } + + fn new() -> Self { + return Self { entries: vec![] }; + } +} + +fn to_display(time_to_empty: battery::units::Time) -> String { + let mut formatted_time_remaining = String::from(":"); + let hours = (time_to_empty.value / 60.0 / 60.0).round(); + if hours > 0.0 { + formatted_time_remaining.push_str(format!(" {hours:.0}h").as_str()) + } + let minutes = (time_to_empty.value / 60.0).rem(60.0).round(); + if minutes > 0.0 { + formatted_time_remaining.push_str(format!(" {minutes:.0}m").as_str()) + } + formatted_time_remaining.push_str(" remaining"); + formatted_time_remaining +} diff --git a/client/src/plugin/resource_monitor/cpu.rs b/client/src/plugin/resource_monitor/cpu.rs new file mode 100644 index 0000000..7fc5463 --- /dev/null +++ b/client/src/plugin/resource_monitor/cpu.rs @@ -0,0 +1,57 @@ +use crate::plugin::utils::Plugin; +use sysinfo::{CpuExt, SystemExt}; + +pub struct CpuPlugin { + sysinfo: sysinfo::System, + entries: Vec, +} + +impl Plugin for CpuPlugin { + fn id() -> &'static str { + return "cpu"; + } + + fn priority() -> u32 { + return 13; + } + + fn title() -> &'static str { + return "󰍛 CPU"; + } + + fn update_timeout() -> Option { + return Some(std::time::Duration::from_secs(2)); + } + + fn entries(&self) -> Vec { + return self.entries.clone(); + } + + fn update_entries(&mut self) -> anyhow::Result<()> { + self.sysinfo.refresh_cpu(); + + self.entries.clear(); + for cpu_core in self.sysinfo.cpus() { + self.entries.push(crate::model::Entry { + id: cpu_core.name().to_string(), + title: format!( + "{}: {}% {}MHz", + cpu_core.name(), + cpu_core.cpu_usage() as i32, + cpu_core.frequency() + ), + action: String::from(""), + meta: String::from("Resource Monitor CPU"), + }); + } + + return Ok(()); + } + + fn new() -> Self { + return Self { + sysinfo: sysinfo::System::new_all(), + entries: vec![], + }; + } +} diff --git a/client/src/plugin/resource_monitor/disks.rs b/client/src/plugin/resource_monitor/disks.rs new file mode 100644 index 0000000..b63bac1 --- /dev/null +++ b/client/src/plugin/resource_monitor/disks.rs @@ -0,0 +1,69 @@ +use crate::plugin::utils::Plugin; +use anyhow::Context; +use sysinfo::{DiskExt, SystemExt}; + +pub struct DisksPlugin { + sysinfo: sysinfo::System, + entries: Vec, +} + +impl Plugin for DisksPlugin { + fn id() -> &'static str { + return "disks"; + } + + fn priority() -> u32 { + return 12; + } + + fn title() -> &'static str { + return "󱛟 Disks"; + } + + fn update_timeout() -> Option { + return Some(std::time::Duration::from_secs(2)); + } + + fn entries(&self) -> Vec { + return self.entries.clone(); + } + + fn update_entries(&mut self) -> anyhow::Result<()> { + self.sysinfo.refresh_all(); + self.entries.clear(); + + for disk in self.sysinfo.disks() { + let mount_point = disk + .mount_point() + .to_str() + .context("Unable to convert mount point path to string.")? + .to_string(); + + let used_space = disk.total_space() - disk.available_space(); + let perentage_used = 100 * used_space / disk.total_space(); + let total_space_in_gb = disk.total_space() as f64 / 10_f64.powf(9.); + let used_space_in_gb = used_space as f64 / 10_f64.powf(9.); + + let title = format!( + "{} {}% ({:.2}gb / {:.2}gb)", + &mount_point, perentage_used, used_space_in_gb, total_space_in_gb + ); + + self.entries.push(crate::model::Entry { + id: mount_point, + title, + action: String::from(""), + meta: String::from("Resource Monitor Disks"), + }); + } + + return Ok(()); + } + + fn new() -> Self { + return Self { + sysinfo: sysinfo::System::new_all(), + entries: vec![], + }; + } +} diff --git a/client/src/plugin/resource_monitor/memory.rs b/client/src/plugin/resource_monitor/memory.rs new file mode 100644 index 0000000..a1700b5 --- /dev/null +++ b/client/src/plugin/resource_monitor/memory.rs @@ -0,0 +1,59 @@ +use crate::plugin::utils::Plugin; +use sysinfo::SystemExt; + +pub struct MemoryPlugin { + sysinfo: sysinfo::System, + entries: Vec, +} + +impl Plugin for MemoryPlugin { + fn id() -> &'static str { + return "memory"; + } + + fn priority() -> u32 { + return 11; + } + + fn title() -> &'static str { + return "󱓱 Memory"; + } + + fn update_timeout() -> Option { + return Some(std::time::Duration::from_secs(2)); + } + + fn entries(&self) -> Vec { + return self.entries.clone(); + } + + fn update_entries(&mut self) -> anyhow::Result<()> { + self.sysinfo.refresh_memory(); + self.entries.clear(); + + let perentage_used = 100 * self.sysinfo.used_memory() / self.sysinfo.total_memory(); + let total_memory_in_gb = self.sysinfo.total_memory() as f64 / 10_f64.powf(9.); + let used_memory_in_gb = self.sysinfo.used_memory() as f64 / 10_f64.powf(9.); + + let title = format!( + "{}% ({:.2}gb / {:.2}gb)", + perentage_used, used_memory_in_gb, total_memory_in_gb + ); + + self.entries.push(crate::model::Entry { + id: String::from("memory"), + title, + action: String::from(""), + meta: String::from("Resource Monitor Memory RAM"), + }); + + return Ok(()); + } + + fn new() -> Self { + return Self { + sysinfo: sysinfo::System::new_all(), + entries: vec![], + }; + } +} diff --git a/client/src/plugin/resource_monitor/mod.rs b/client/src/plugin/resource_monitor/mod.rs new file mode 100644 index 0000000..1f3a9f7 --- /dev/null +++ b/client/src/plugin/resource_monitor/mod.rs @@ -0,0 +1,4 @@ +pub mod battery; +pub mod cpu; +pub mod disks; +pub mod memory; diff --git a/client/src/plugin/utils.rs b/client/src/plugin/utils.rs index 2f747eb..063d695 100644 --- a/client/src/plugin/utils.rs +++ b/client/src/plugin/utils.rs @@ -1,4 +1,155 @@ +use anyhow::Context; use fuzzy_matcher::FuzzyMatcher; +use iced::futures::StreamExt; + +pub fn spawn( +) -> iced::Subscription { + return iced::subscription::channel( + std::any::TypeId::of::(), + 100, + |plugin_channel_out| async move { + let mut plugin = PluginType::new(); + + let main_loop_result = plugin.main(plugin_channel_out).await; + if let Err(error) = main_loop_result { + log::error!( + target: PluginType::id(), + "{:?}", error, + ); + panic!(); + } + + loop { + unreachable!(); + } + }, + ); +} + +#[async_trait::async_trait] +pub trait Plugin { + fn id() -> &'static str; + fn priority() -> u32; + fn title() -> &'static str; + fn update_timeout() -> Option { + return None; + } + + fn new() -> Self; + + fn entries(&self) -> Vec; + + fn update_entries(&mut self) -> anyhow::Result<()> { + return Ok(()); + } + + fn plugin( + &self, + app_channel_out: &mut iced::futures::channel::mpsc::Sender, + ) -> crate::model::Plugin { + return crate::model::Plugin { + id: String::from(Self::id()), + priority: Self::priority(), + title: String::from(Self::title()), + app_channel_out: app_channel_out.clone(), + entries: self.entries(), + }; + } + + async fn main( + &mut self, + mut plugin_channel_out: iced::futures::channel::mpsc::Sender, + ) -> anyhow::Result<()> { + self.update_entries()?; + + let (mut app_channel_out, mut plugin_channel_in) = + iced::futures::channel::mpsc::channel(100); + self.register_plugin(&mut plugin_channel_out, &mut app_channel_out)?; + let mut last_query = String::from(""); + + loop { + self.update( + &mut plugin_channel_out, + &mut plugin_channel_in, + &mut last_query, + ) + .await?; + } + } + + fn register_plugin( + &mut self, + plugin_channel_out: &mut iced::futures::channel::mpsc::Sender, + app_channel_out: &mut iced::futures::channel::mpsc::Sender, + ) -> anyhow::Result<()> { + plugin_channel_out + .try_send(crate::Message::RegisterPlugin(self.plugin(app_channel_out))) + .context("Failed to send message to register plugin.")?; + + return Ok(()); + } + + async fn update( + &mut self, + plugin_channel_out: &mut iced::futures::channel::mpsc::Sender, + plugin_channel_in: &mut iced::futures::channel::mpsc::Receiver, + last_query: &mut String, + ) -> anyhow::Result<()> { + let plugin_request_future = plugin_channel_in.select_next_some(); + let plugin_request = match Self::update_timeout() { + Some(update_timeout) => { + async_std::future::timeout(update_timeout, plugin_request_future) + .await + .unwrap_or(crate::model::PluginRequest::Timeout) + } + None => plugin_request_future.await, + }; + + match plugin_request { + crate::model::PluginRequest::Search(query) => { + self.search(&query, plugin_channel_out)?; + *last_query = query; + } + crate::model::PluginRequest::Timeout => { + self.update_entries()?; + self.search(last_query, plugin_channel_out)?; + } + crate::model::PluginRequest::Activate(entry_id) => { + self.activate(entry_id, plugin_channel_out)? + } + } + + return Ok(()); + } + + fn search( + &mut self, + query: &String, + plugin_channel_out: &mut iced::futures::channel::mpsc::Sender, + ) -> anyhow::Result<()> { + let filtered_entries = crate::plugin::utils::search(self.entries(), query); + + plugin_channel_out + .try_send(crate::Message::UpdateEntries( + String::from(Self::id()), + filtered_entries, + )) + .context(format!( + "Failed to send message to update entries while searching for '{}'.", + query + ))?; + + return Ok(()); + } + + fn activate( + &mut self, + _entry_id: String, + _plugin_channel_out: &mut iced::futures::channel::mpsc::Sender, + ) -> anyhow::Result<()> { + return Ok(()); + } +} pub fn search(entries: Vec, query: &String) -> Vec { let matcher = fuzzy_matcher::skim::SkimMatcherV2::default(); diff --git a/client/src/plugin/windows.rs b/client/src/plugin/windows.rs index 96720cb..c262eab 100644 --- a/client/src/plugin/windows.rs +++ b/client/src/plugin/windows.rs @@ -1,68 +1,61 @@ +use crate::plugin::utils::Plugin; use anyhow::Context; -use iced::futures::StreamExt; -pub struct Plugin { - plugin: crate::model::Plugin, - plugin_channel_out: iced::futures::channel::mpsc::Sender, - plugin_channel_in: iced::futures::channel::mpsc::Receiver, +pub struct WindowsPlugin { sway: swayipc::Connection, + entries: Vec, } -impl Plugin { - pub fn spawn() -> iced::Subscription { - return iced::subscription::channel( - std::any::TypeId::of::(), - 100, - |plugin_channel_out| async { - let mut plugin = Plugin::new(plugin_channel_out); - plugin.main().await - }, - ); +impl WindowsPlugin { + fn get_window_nodes(node: swayipc::Node) -> Vec { + if !node.nodes.is_empty() { + return node + .nodes + .into_iter() + .flat_map(|n| Self::get_window_nodes(n)) + .collect(); + } + + if node.node_type == swayipc::NodeType::Con { + return vec![node]; + } + + return vec![]; + } +} + +impl Plugin for WindowsPlugin { + fn id() -> &'static str { + return "windows"; + } + fn priority() -> u32 { + return 30; + } + fn title() -> &'static str { + return "󰖯 Windows"; } - pub fn new( - plugin_channel_out: iced::futures::channel::mpsc::Sender, - ) -> Plugin { - let (app_channel_out, plugin_channel_in) = iced::futures::channel::mpsc::channel(100); + fn entries(&self) -> Vec { + return self.entries.clone(); + } - let connection_result = swayipc::Connection::new(); + fn new() -> Self { + let connection_result = + swayipc::Connection::new().context("Failed to establish sway ipc connection."); if let Err(error) = connection_result { - log::error!( - target: "windows", - "{:?}", error, - ); + log::error!(target: Self::id(), "{:?}", error); panic!(); } let mut sway = connection_result.unwrap(); - let entries_result = Plugin::all_entries(&mut sway); - if let Err(error) = entries_result { - log::error!( - target: "windows", - "{:?}", error, - ); + let root_node_result = sway.get_tree().context("Failed to get_tree from sway ipc."); + if let Err(error) = root_node_result { + log::error!(target: Self::id(), "{:?}", error); panic!(); } - let entries = entries_result.unwrap(); + let root_node = root_node_result.unwrap(); - return Plugin { - plugin_channel_in, - plugin_channel_out, - plugin: crate::model::Plugin { - id: String::from("windows"), - priority: 30, - title: String::from("󰖯 Windows"), - app_channel_out, - entries, - }, - sway, - }; - } - - fn all_entries(sway: &mut swayipc::Connection) -> anyhow::Result> { - let root_node = sway.get_tree()?; - - let entries = Plugin::get_window_nodes(root_node) + let entries = Self::get_window_nodes(root_node) .into_iter() .map(|node| { let name = node @@ -71,93 +64,24 @@ impl Plugin { let app_id = node .app_id .unwrap_or(String::from("-- window app_id missing --")); - let title = if name != "" { name } else { app_id }; + let title = if !name.is_empty() { name } else { app_id }; return crate::model::Entry { id: node.id.to_string(), title, action: String::from("focus"), - meta: String::from("windows"), + meta: String::from(Self::id()), }; }) .collect(); - return Ok(entries); - } - - fn get_window_nodes(node: swayipc::Node) -> Vec { - if !node.nodes.is_empty() { - return node - .nodes - .into_iter() - .flat_map(|n| Plugin::get_window_nodes(n)) - .collect(); - } - - if node.node_type == swayipc::NodeType::Con { - return vec![node]; - } - - return vec![]; - } - - async fn main(&mut self) -> ! { - let register_plugin_result = self.register_plugin(); - if let Err(error) = register_plugin_result { - log::error!( - target: self.plugin.id.as_str(), - "{:?}", error, - ); - panic!(); - } - - loop { - let update_result = self.update().await; - if let Err(error) = update_result { - log::warn!( - target: self.plugin.id.as_str(), - "{:?}", error, - ); - } - } - } - - fn register_plugin(&mut self) -> anyhow::Result<()> { - self.plugin_channel_out - .try_send(crate::Message::RegisterPlugin(self.plugin.clone())) - .context("Failed to send message to register plugin.")?; - - return Ok(()); - } - - async fn update(&mut self) -> anyhow::Result<()> { - let plugin_request = self.plugin_channel_in.select_next_some().await; - - match plugin_request { - crate::model::PluginRequest::Search(query) => self.search(&query)?, - crate::model::PluginRequest::Timeout => (), - crate::model::PluginRequest::Activate(entry_id) => self.activate(entry_id)?, - } - - return Ok(()); - } - - fn search(&mut self, query: &String) -> anyhow::Result<()> { - let filtered_entries = crate::plugin::utils::search(self.plugin.entries.clone(), query); - - self.plugin_channel_out - .try_send(crate::Message::UpdateEntries( - self.plugin.id.clone(), - filtered_entries, - )) - .context(format!( - "Failed to send message to update entries while searching for '{}'.", - query - ))?; - - return Ok(()); + return Self { sway, entries }; } - fn activate(&mut self, entry_id: String) -> anyhow::Result<()> { + fn activate( + &mut self, + entry_id: String, + plugin_channel_out: &mut iced::futures::channel::mpsc::Sender, + ) -> anyhow::Result<()> { self.sway .run_command(format!("[con_id={}] focus", entry_id)) .context(format!( @@ -165,7 +89,7 @@ impl Plugin { entry_id ))?; - self.plugin_channel_out + plugin_channel_out .try_send(crate::Message::Exit) .context(format!( "Failed to send message to exit application while activating entry with id '{}'.",