diff --git a/src/drun/mod.rs b/src/drun/mod.rs index ab940fc..617a669 100644 --- a/src/drun/mod.rs +++ b/src/drun/mod.rs @@ -10,6 +10,10 @@ pub struct DesktopEntry { } impl LauncherListItem for DesktopEntry { + fn id(&self) -> String { + self.id.clone() + } + fn title(&self) -> String { return self.name.to_owned(); } diff --git a/src/launcher/mod.rs b/src/launcher/mod.rs index 1266f32..2f3cf9f 100644 --- a/src/launcher/mod.rs +++ b/src/launcher/mod.rs @@ -7,6 +7,7 @@ pub struct WaycastLauncher { plugins_show_always: Vec>, plugins_by_prefix: HashMap>, current_results: Vec>, + current_results_by_id: HashMap, } impl WaycastLauncher { @@ -16,6 +17,7 @@ impl WaycastLauncher { plugins_show_always: Vec::new(), plugins_by_prefix: HashMap::new(), current_results: Vec::new(), + current_results_by_id: HashMap::new(), } } } @@ -47,23 +49,39 @@ impl WaycastLauncher { self } - pub fn get_default_results(&mut self) -> &Vec> { + fn add_current_item(&mut self, item: Box) { + let id = item.id(); + let index = self.current_results.len(); + self.current_results.push(item); + self.current_results_by_id.insert(id, index); + } + + fn clear_current_results(&mut self) { self.current_results.clear(); + self.current_results_by_id.clear(); + } + + pub fn get_default_results(&mut self) -> &Vec> { + self.clear_current_results(); + let mut all_entries = Vec::new(); for plugin in &self.plugins_show_always { - for entry in plugin.default_list() { - self.current_results.push(entry); - } + all_entries.extend(plugin.default_list()); + } + for entry in all_entries { + self.add_current_item(entry); } &self.current_results } pub fn search(&mut self, query: &str) -> &Vec> { - self.current_results.clear(); + self.clear_current_results(); + let mut all_entries = Vec::new(); for plugin in &self.plugins { - for entry in plugin.filter(query) { - self.current_results.push(entry); - } + all_entries.extend(plugin.filter(query)); + } + for entry in all_entries { + self.add_current_item(entry); } &self.current_results @@ -77,6 +95,18 @@ impl WaycastLauncher { } } + pub fn execute_item_by_id(&self, id: &str) -> Result<(), crate::LaunchError> { + if let Some(&index) = self.current_results_by_id.get(id) { + if let Some(item) = self.current_results.get(index) { + item.execute() + } else { + Err(crate::LaunchError::CouldNotLaunch("Item index out of bounds".into())) + } + } else { + Err(crate::LaunchError::CouldNotLaunch("Item not found".into())) + } + } + pub fn current_results(&self) -> &Vec> { &self.current_results } diff --git a/src/lib.rs b/src/lib.rs index 57327c9..433755d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,6 +9,7 @@ pub enum LaunchError { } pub trait LauncherListItem { + fn id(&self) -> String; fn title(&self) -> String; fn description(&self) -> Option; fn execute(&self) -> Result<(), LaunchError>; diff --git a/src/plugins/drun.rs b/src/plugins/drun.rs index 7d5a220..1bc9bdf 100644 --- a/src/plugins/drun.rs +++ b/src/plugins/drun.rs @@ -11,6 +11,10 @@ pub struct DesktopEntry { } impl LauncherListItem for DesktopEntry { + fn id(&self) -> String { + self.id.clone() + } + fn title(&self) -> String { return self.name.to_owned(); } diff --git a/src/plugins/file_search.rs b/src/plugins/file_search.rs index 53308e4..4c34954 100644 --- a/src/plugins/file_search.rs +++ b/src/plugins/file_search.rs @@ -21,6 +21,10 @@ impl FileEntry { } impl LauncherListItem for FileEntry { + fn id(&self) -> String { + self.path.to_string_lossy().to_string() + } + fn title(&self) -> String { return String::from(self.path.file_name().unwrap().to_string_lossy()); } diff --git a/src/ui/gtk/mod.rs b/src/ui/gtk/mod.rs index 614b724..6fafb92 100644 --- a/src/ui/gtk/mod.rs +++ b/src/ui/gtk/mod.rs @@ -26,7 +26,7 @@ mod imp { pub title: RefCell, pub description: RefCell>, pub icon: RefCell, - pub index: RefCell, // Store index to access original entry + pub id: RefCell, // Store id to access original entry } #[glib::object_subclass] @@ -44,7 +44,7 @@ glib::wrapper! { } impl LauncherItemObject { - pub fn new(title: String, description: Option, icon: String, index: usize) -> Self { + pub fn new(title: String, description: Option, icon: String, id: String) -> Self { let obj: Self = glib::Object::new(); let imp = obj.imp(); @@ -52,7 +52,7 @@ impl LauncherItemObject { *imp.title.borrow_mut() = title; *imp.description.borrow_mut() = description; *imp.icon.borrow_mut() = icon; - *imp.index.borrow_mut() = index; + *imp.id.borrow_mut() = id; obj } @@ -69,8 +69,8 @@ impl LauncherItemObject { self.imp().description.borrow().clone() } - pub fn index(&self) -> usize { - *self.imp().index.borrow() + pub fn id(&self) -> String { + self.imp().id.borrow().clone() } } @@ -234,12 +234,12 @@ impl GtkLauncherUI { // Update the list store list_store_for_search.remove_all(); - for (index, entry) in results.iter().enumerate() { + for entry in results.iter() { let item_obj = LauncherItemObject::new( entry.title(), entry.description(), entry.icon(), - index, + entry.id(), ); list_store_for_search.append(&item_obj); } @@ -252,8 +252,8 @@ impl GtkLauncherUI { search_input.connect_activate(move |_| { if let Some(selected_item) = selection_for_enter.selected_item() { if let Some(item_obj) = selected_item.downcast_ref::() { - let index = item_obj.index(); - match launcher_for_enter.borrow().execute_item(index) { + let id = item_obj.id(); + match launcher_for_enter.borrow().execute_item_by_id(&id) { Ok(_) => app_for_enter.quit(), Err(e) => eprintln!("Failed to launch app: {:?}", e), } @@ -304,22 +304,25 @@ impl GtkLauncherUI { // Connect list activation signal let launcher_for_activate = launcher.clone(); let app_for_activate = app.clone(); + let list_store_for_activate = list_store.clone(); list_view.connect_activate(move |_, position| { - match launcher_for_activate - .borrow() - .execute_item(position as usize) - { - Ok(_) => app_for_activate.quit(), - Err(e) => eprintln!("Failed to launch app: {:?}", e), + if let Some(obj) = list_store_for_activate.item(position) { + if let Some(item_obj) = obj.downcast_ref::() { + let id = item_obj.id(); + match launcher_for_activate.borrow().execute_item_by_id(&id) { + Ok(_) => app_for_activate.quit(), + Err(e) => eprintln!("Failed to launch app: {:?}", e), + } + } } }); // Initialize with default results let mut launcher_ref = launcher.borrow_mut(); let results = launcher_ref.get_default_results(); - for (index, entry) in results.iter().enumerate() { + for entry in results.iter() { let item_obj = - LauncherItemObject::new(entry.title(), entry.description(), entry.icon(), index); + LauncherItemObject::new(entry.title(), entry.description(), entry.icon(), entry.id()); list_store.append(&item_obj); }