|
1 | 1 | // Copyright 2021 System76 <[email protected]>
|
2 | 2 | // SPDX-License-Identifier: MPL-2.0
|
3 | 3 |
|
| 4 | +//! # pop-launcher-toolkit |
| 5 | +//! |
| 6 | +//! A toolkit to write pop-launcher client and plugin. |
| 7 | +//! |
| 8 | +//! ## Crates |
| 9 | +//! - **[`launcher`]:** re-export the pop-launcher crate, containing all the IPC message struct and |
| 10 | +//! some utility functions to locate plugins. |
| 11 | +//! - **[`service`]:** re-export the pop-launcher-service crate, containing deserializable plugin config struct. |
| 12 | +//! This is useful if your client needs to read user defined plugins configs. |
| 13 | +//! - **[`plugins`]:** re-export pop-launcher-plugins which defines all the default pop-launcher plugins. |
| 14 | +//! Useful if your client needs to read default plugin configs |
| 15 | +//! |
| 16 | +//! ## Writing a plugin |
| 17 | +//! |
| 18 | +//! Add the following to your Cargo.toml : |
| 19 | +//! |
| 20 | +//! ```toml |
| 21 | +//! [dependencies] |
| 22 | +//! tokio = { version = "1.18.2", features = ["rt"] } |
| 23 | +//! pop-launcher-toolkit = { git = "https://github.com/pop-os/launcher" } |
| 24 | +//! ``` |
| 25 | +//! |
| 26 | +//! And implement the [`PluginExt`] trait: |
| 27 | +//! |
| 28 | +//! [`PluginExt`]: plugin_trait::PluginExt |
| 29 | +//! |
| 30 | +//! ```rust |
| 31 | +//! use pop_launcher_toolkit::launcher::{Indice, PluginResponse, PluginSearchResult}; |
| 32 | +//! use pop_launcher_toolkit::plugin_trait::{async_trait, PluginExt}; |
| 33 | +//! use pop_launcher_toolkit::plugins; |
| 34 | +//! |
| 35 | +//! // The plugin struct, here it holds the search result |
| 36 | +//! pub struct MyPlugin { |
| 37 | +//! data: Vec<String> |
| 38 | +//! } |
| 39 | +//! |
| 40 | +//! #[async_trait] |
| 41 | +//! impl PluginExt for MyPlugin { |
| 42 | +//! |
| 43 | +//! // Define the name of you plugin, this will be used |
| 44 | +//! // to generate a logfile in $XDG_STATE_HOME at runtime. |
| 45 | +//! fn name(&self) -> &str { |
| 46 | +//! "my_awesome_plugin" |
| 47 | +//! } |
| 48 | +//! |
| 49 | +//! // Respond to `pop-launcher` 'search' query |
| 50 | +//! async fn search(&mut self, query: &str) { |
| 51 | +//! // `pop-launcher` dispatches request to plugins according to the regex defined in |
| 52 | +//! // the `plugin.ron` config file, here we get rid of the prefix |
| 53 | +//! // before processing the request. |
| 54 | +//! let query = query.strip_prefix("plug ").unwrap(); |
| 55 | +//! |
| 56 | +//! // Iterate through our internal search results with their indices. |
| 57 | +//! let search_results = self.data.iter() |
| 58 | +//! .enumerate() |
| 59 | +//! .filter(|(idx, data)| data.contains(query)); |
| 60 | +//! |
| 61 | +//! // Send our search results to `pop-launcher` using their indices as id. |
| 62 | +//! for (idx, search_result) in search_results { |
| 63 | +//! self.respond_with(PluginResponse::Append(PluginSearchResult { |
| 64 | +//! id: idx as u32, |
| 65 | +//! name: search_result.clone(), |
| 66 | +//! description: "".to_string(), |
| 67 | +//! keywords: None, |
| 68 | +//! icon: None, |
| 69 | +//! exec: None, |
| 70 | +//! window: None, |
| 71 | +//! })).await; |
| 72 | +//! } |
| 73 | +//! |
| 74 | +//! // tell `pop-launcher` we are done with this request |
| 75 | +//! self.respond_with(PluginResponse::Finished).await; |
| 76 | +//! } |
| 77 | +//! |
| 78 | +//! // Respond to `pop-launcher` 'activate' query |
| 79 | +//! async fn activate(&mut self, id: Indice) { |
| 80 | +//! // Get the selected entry |
| 81 | +//! let entry = self.data.get(id as usize).unwrap(); |
| 82 | +//! // Here we use xdg_open to run the entry but this could be anything |
| 83 | +//! plugins::xdg_open(entry); |
| 84 | +//! // Tell pop launcher we are done |
| 85 | +//! self.respond_with(PluginResponse::Finished); |
| 86 | +//! } |
| 87 | +//! |
| 88 | +//! // Respond to `pop-launcher` 'close' request. |
| 89 | +//! async fn quit(&mut self, id: Indice) { |
| 90 | +//! self.respond_with(PluginResponse::Close).await; |
| 91 | +//! } |
| 92 | +//! } |
| 93 | +//! |
| 94 | +//! #[tokio::main(flavor = "current_thread")] |
| 95 | +//! pub async fn main() { |
| 96 | +//! |
| 97 | +//! // Here we declare our plugin with dummy values, and never mutate them. |
| 98 | +//! // In a real plugin we would probably use some kind of mutable shared reference to |
| 99 | +//! // update our search results. |
| 100 | +//! let mut plugin = MyPlugin { |
| 101 | +//! data: vec!["https://crates.io".to_string(), "https://en.wikipedia.org".to_string()], |
| 102 | +//! }; |
| 103 | +//! |
| 104 | +//! /// If you need to debug your plugin or display error messages use `tcracing` macros. |
| 105 | +//! tracing::info!("Starting my_awsome_plugin"); |
| 106 | +//! |
| 107 | +//! // Call the plugin entry point function to start |
| 108 | +//! // talking with pop_launcherc |
| 109 | +//! plugin.run().await; |
| 110 | +//! } |
| 111 | +//! ``` |
| 112 | +
|
| 113 | +pub use pop_launcher as launcher; |
| 114 | +pub use pop_launcher_plugins as plugins; |
4 | 115 | pub use pop_launcher_service::{
|
5 |
| - self as service, |
6 |
| - load::from_path as load_plugin_from_path, |
7 |
| - load::from_paths as load_plugins_from_paths |
| 116 | + self as service, load::from_path as load_plugin_from_path, |
| 117 | + load::from_paths as load_plugins_from_paths, |
8 | 118 | };
|
9 |
| -pub use pop_launcher_plugins as plugins; |
10 |
| -pub use pop_launcher as launcher; |
| 119 | + |
| 120 | +/// A helper trait to quickly create `pop-launcher` plugins |
| 121 | +pub mod plugin_trait; |
0 commit comments