diff --git a/espanso-modulo/src/search/algorithm.rs b/espanso-modulo/src/search/algorithm.rs
index 65d4845..4f57637 100644
--- a/espanso-modulo/src/search/algorithm.rs
+++ b/espanso-modulo/src/search/algorithm.rs
@@ -17,14 +17,25 @@
* along with modulo. If not, see .
*/
+use std::collections::HashSet;
+
use crate::sys::search::types::SearchItem;
-pub fn get_algorithm(name: &str) -> Box Vec> {
- match name {
+pub fn get_algorithm(
+ name: &str,
+ use_command_filter: bool,
+) -> Box Vec> {
+ let search_algorithm: Box Vec> = match name {
"exact" => Box::new(exact_match),
"iexact" => Box::new(case_insensitive_exact_match),
"ikey" => Box::new(case_insensitive_keyword),
_ => panic!("unknown search algorithm: {}", name),
+ };
+
+ if use_command_filter {
+ command_filter(search_algorithm)
+ } else {
+ search_algorithm
}
}
@@ -78,3 +89,36 @@ fn case_insensitive_keyword(query: &str, items: &[SearchItem]) -> Vec {
.map(|(i, _)| i)
.collect()
}
+
+fn command_filter(
+ search_algorithm: Box Vec>,
+) -> Box Vec> {
+ Box::new(move |query, items| {
+ let (valid_ids, trimmed_query) = if query.starts_with('>') {
+ (
+ items
+ .iter()
+ .enumerate()
+ .filter(|(_, item)| item.is_builtin)
+ .map(|(i, _)| i).collect::>(),
+ query.trim_start_matches('>'),
+ )
+ } else {
+ (
+ items
+ .iter()
+ .enumerate()
+ .filter(|(_, item)| !item.is_builtin)
+ .map(|(i, _)| i).collect::>(),
+ query,
+ )
+ };
+
+ let results = search_algorithm(trimmed_query, &items);
+
+ results
+ .into_iter()
+ .filter(|id| valid_ids.contains(id))
+ .collect()
+ })
+}
diff --git a/espanso-modulo/src/search/config.rs b/espanso-modulo/src/search/config.rs
index 3f32ce6..c0b8a67 100644
--- a/espanso-modulo/src/search/config.rs
+++ b/espanso-modulo/src/search/config.rs
@@ -55,4 +55,7 @@ pub struct SearchItem {
pub id: String,
pub label: String,
pub trigger: Option,
+
+ #[serde(default)]
+ pub is_builtin: bool,
}
diff --git a/espanso-modulo/src/search/generator.rs b/espanso-modulo/src/search/generator.rs
index 3a8ddf9..596a0c8 100644
--- a/espanso-modulo/src/search/generator.rs
+++ b/espanso-modulo/src/search/generator.rs
@@ -28,6 +28,7 @@ pub fn generate(config: SearchConfig) -> types::Search {
id: item.id,
label: item.label,
trigger: item.trigger,
+ is_builtin: item.is_builtin,
})
.collect();
diff --git a/espanso-modulo/src/sys/search/mod.rs b/espanso-modulo/src/sys/search/mod.rs
index cdbed5e..d8c99a6 100644
--- a/espanso-modulo/src/sys/search/mod.rs
+++ b/espanso-modulo/src/sys/search/mod.rs
@@ -26,6 +26,7 @@ pub mod types {
pub id: String,
pub label: String,
pub trigger: Option,
+ pub is_builtin: bool,
}
#[derive(Debug)]
diff --git a/espanso-modulo/src/sys/search/search.cpp b/espanso-modulo/src/sys/search/search.cpp
index 3f86cf3..9daadad 100644
--- a/espanso-modulo/src/sys/search/search.cpp
+++ b/espanso-modulo/src/sys/search/search.cpp
@@ -44,6 +44,8 @@ const int SEARCH_BAR_FONT_SIZE = 20;
const long DEFAULT_STYLE = wxSTAY_ON_TOP | wxFRAME_TOOL_WINDOW | wxBORDER_NONE;
#endif
+const int HELP_TEXT_FONT_SIZE = 10;
+
const wxColour SELECTION_LIGHT_BG = wxColour(164, 210, 253);
const wxColour SELECTION_DARK_BG = wxColour(49, 88, 126);
@@ -138,6 +140,7 @@ public:
wxPanel *panel;
wxTextCtrl *searchBar;
wxStaticBitmap *iconPanel;
+ wxStaticText *helpText;
ResultListBox *resultBox;
void SetItems(SearchItem *items, int itemSize);
@@ -219,6 +222,12 @@ SearchFrame::SearchFrame(const wxString &title, const wxPoint &pos, const wxSize
vbox->Add(topBox, 1, wxEXPAND);
+ helpText = new wxStaticText(panel, wxID_ANY, "Search matches by content or trigger (or type > to see commands)");
+ vbox->Add(helpText, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 10);
+ wxFont helpFont = helpText->GetFont();
+ helpFont.SetPointSize(HELP_TEXT_FONT_SIZE);
+ helpText->SetFont(helpFont);
+
wxArrayString choices;
int resultId = NewControlId();
resultBox = new ResultListBox(panel, isDark, resultId, wxDefaultPosition, wxSize(MIN_WIDTH, MIN_HEIGHT));
@@ -299,6 +308,12 @@ void SearchFrame::OnCharEvent(wxKeyEvent &event)
void SearchFrame::OnQueryChange(wxCommandEvent &event)
{
+ if (helpText != nullptr) {
+ helpText->Destroy();
+ panel->Layout();
+ helpText = nullptr;
+ }
+
wxString queryString = searchBar->GetValue();
const char *query = queryString.ToUTF8();
queryCallback(query, (void *)this, data);