1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
//! The crate aims to provide an easy to use wrapper around the GNOME Shell Search Provider DBus interface.
//!
//! - [Writing a Search Provider tutorial](https://developer.gnome.org/documentation/tutorials/search-provider.html)
//!
//!
//! # How to use
//!
//! - [Register a new search provider](https://developer.gnome.org/documentation/tutorials/search-provider.html#registering-a-new-search-provider)
//! - Implement the [`SearchProviderImpl`] trait for the struct that holds your Application.
//! - Once the application is installed, enable it in GNOME Settings -> Search.
//!
//! ```
//! use search_provider::{ResultID, ResultMeta, SearchProviderImpl};
//! use std::collections::HashMap;
//!
//! #[derive(Debug)]
//! struct Application {
//!     results: HashMap<String, String>,
//! }
//! impl SearchProviderImpl for Application {
//!     fn activate_result(&self, identifier: ResultID, terms: &[String], timestamp: u32) {
//!         let result = self.results.get(&identifier);
//!         println!(
//!             "activating result {:#?} identified by {}",
//!             result, identifier
//!         );
//!     }
//!
//!     fn initial_result_set(&self, terms: &[String]) -> Vec<ResultID> {
//!         // Here do your search logic
//!         if terms.contains(&"some_value".to_owned()) {
//!             vec!["some_key".to_owned()]
//!         } else {
//!             vec![]
//!         }
//!     }
//!
//!     fn result_metas(&self, identifiers: &[ResultID]) -> Vec<ResultMeta> {
//!         self.results
//!             .iter()
//!             .map(|(identifier, value)| {
//!                 ResultMeta::builder(identifier.to_owned(), "Some name")
//!                     .description("Some description of the current identifier")
//!                     .build()
//!             })
//!             .collect::<Vec<_>>()
//!     }
//! }
//! ```
//!
//! - Create an instance of [`SearchProvider`]
//!
//! ```ignore
//! use search_provider::SearchProvider;
//! use std::collections::HashMap;
//!
//! async fn main_entry() -> zbus::Result<()> {
//!     let mut results = HashMap::new();
//!     results.insert("some_key".to_string(), "some_value".to_string());
//!     let app = Application { results };
//!     let provider = SearchProvider::new(
//!         app,
//!         "org.gnome.design.IconLibrary.SearchProvider",
//!         "/org/gnome/design/IconLibrary/SearchProvider",
//!     )
//!     .await?;
//!     Ok(())
//! }
//! ```

mod search_provider;
pub use crate::search_provider::SearchProvider;

mod result_metadata;
pub use crate::result_metadata::{IconData, ResultMeta, ResultMetaBuilder};

/// A result identifier.
pub type ResultID = String;

/// A trait to implement to communicate with the search provider
/// interface.
pub trait SearchProviderImpl {
    /// The method is called when a user clicks on an individual search result
    /// to open it in the application.
    ///
    /// # Arguments
    ///
    /// * `identifier` - the result ID.
    /// * `terms` - current search terms.
    /// * `timestamp` - current timestamp.
    fn activate_result(&self, identifier: ResultID, terms: &[String], timestamp: u32);

    /// The method is called when a new search is started.
    ///
    /// # Arguments
    ///
    /// * `terms` - current search terms.
    /// * `timestamp` - current timestamp.
    ///
    /// # Returns
    ///
    /// A list of search results IDs. GNOME Shell, will call [`result_metas()`](SearchProviderImpl::result_metas`)
    /// on some of those IDs to retrieve the corresponding [`ResultMeta`].
    #[doc(alias = "get_initial_result_set")]
    fn initial_result_set(&self, terms: &[String]) -> Vec<ResultID>;

    /// The method is called to refine the initial search results when more characters were typed
    /// in the search entry.
    ///
    /// # Arguments
    ///
    /// * `previous_results` - list of results ID returned by a previous call to [`initial_result_set()`](SearchProviderImpl::initial_result_set`).
    /// * `terms` - current search terms.
    ///
    /// # Returns
    ///
    /// A list of search results IDs. GNOME Shell, will call [`result_metas()`](SearchProviderImpl::result_metas`)
    /// on some of those IDs to retrieve the corresponding [`ResultMeta`].
    ///
    /// By default the method calls [`initial_result_set()`](SearchProviderImpl::initial_result_set`).
    #[doc(alias = "get_subsearch_result_set")]
    fn subsearch_result_set(
        &self,
        _previous_results: &[ResultID],
        terms: &[String],
    ) -> Vec<ResultID> {
        self.initial_result_set(terms)
    }

    /// The method is called to obtain detailed information of the results.
    ///
    /// # Arguments
    ///
    /// * `identifiers` - search result IDs.
    ///
    /// # Returns
    ///
    /// A list of their correspoding [`ResultMeta`], see [`ResultMeta::builder`] on how to construct one.
    #[doc(alias = "get_result_metas")]
    fn result_metas(&self, identifiers: &[ResultID]) -> Vec<ResultMeta>;

    /// The method is called when a user clicks on the provider icon to
    /// display more search results in the application.
    ///
    /// # Arguments
    ///
    /// * `terms` - current search terms.
    /// * `timestamp` - current timestamp.
    ///
    /// By default the method does nothing.
    fn launch_search(&self, _terms: &[String], _timestamp: u32) {}
}