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);