1+ use crate :: actions:: Action ;
12use crate :: gui:: LauncherApp ;
23use eframe:: egui;
4+ use std:: collections:: HashSet ;
35
46#[ derive( Default ) ]
57pub struct HelpWindow {
@@ -70,12 +72,6 @@ impl HelpWindow {
7072 . show ( ctx, |ui| {
7173 ui. vertical_centered ( |ui| ui. heading ( "Available commands" ) ) ;
7274 ui. separator ( ) ;
73- ui. label (
74- "Tip: Settings \u{2192} Dashboard \u{2192} Customize Dashboard... opens the \
75- widget editor where you can configure plugin-aware defaults for notes, todos \
76- or weather.",
77- ) ;
78- ui. separator ( ) ;
7975 if ui
8076 . checkbox ( & mut self . show_examples , "Show examples" )
8177 . changed ( )
@@ -90,27 +86,47 @@ impl HelpWindow {
9086 ui. text_edit_singleline ( & mut self . filter ) ;
9187 } ) ;
9288 ui. separator ( ) ;
89+ let mut command_map = std:: collections:: HashMap :: new ( ) ;
90+ for plugin in app. plugins . iter ( ) {
91+ command_map. insert ( plugin. name ( ) . to_string ( ) , plugin. commands ( ) ) ;
92+ }
9393 let mut infos = app. plugins . plugin_infos ( ) ;
9494 infos. sort_by ( |a, b| a. 0 . cmp ( & b. 0 ) ) ;
9595 let area_height = ui. available_height ( ) ;
9696 egui:: ScrollArea :: vertical ( )
9797 . max_height ( area_height)
9898 . show ( ui, |ui| {
9999 let filt = self . filter . to_lowercase ( ) ;
100- for ( name, desc, _) in infos {
101- if !filt. is_empty ( )
102- && !name. to_lowercase ( ) . contains ( & filt)
103- && !desc. to_lowercase ( ) . contains ( & filt)
104- {
100+ for ( name, desc, capabilities) in infos {
101+ let commands = command_map. get ( & name) . cloned ( ) . unwrap_or_default ( ) ;
102+ if !matches_filter ( & filt, & name, & desc, & capabilities, & commands) {
105103 continue ;
106104 }
105+ let prefixes = command_prefixes ( & commands) ;
107106 ui. label ( egui:: RichText :: new ( & name) . strong ( ) ) ;
108107 ui. label ( desc) ;
109- if self . show_examples {
110- if let Some ( examples) = example_queries ( & name) {
111- for ex in examples {
112- ui. monospace ( format ! ( " {ex}" ) ) ;
113- }
108+ if capabilities. is_empty ( ) {
109+ ui. label ( "Capabilities: none" ) ;
110+ } else {
111+ ui. label ( format ! ( "Capabilities: {}" , capabilities. join( ", " ) ) ) ;
112+ }
113+ if prefixes. is_empty ( ) {
114+ ui. label ( "Prefixes: none" ) ;
115+ } else {
116+ ui. label ( format ! ( "Prefixes: {}" , prefixes. join( ", " ) ) ) ;
117+ }
118+ if commands. is_empty ( ) {
119+ ui. label ( "Usage: none" ) ;
120+ } else {
121+ ui. label ( "Usage:" ) ;
122+ for command in & commands {
123+ ui. monospace ( format ! ( " {}" , command. label) ) ;
124+ }
125+ }
126+ if self . show_examples && !commands. is_empty ( ) {
127+ ui. label ( "Examples:" ) ;
128+ for command in & commands {
129+ ui. monospace ( format ! ( " {}" , example_line( command) ) ) ;
114130 }
115131 }
116132 ui. separator ( ) ;
@@ -121,98 +137,49 @@ impl HelpWindow {
121137 }
122138}
123139
124- fn example_queries ( name : & str ) -> Option < & ' static [ & ' static str ] > {
125- match name {
126- "web_search" => Some ( & [ "g rust" ] ) ,
127- "runescape_search" => Some ( & [ "rs dragon scimitar" , "osrs agility guide" ] ) ,
128- "youtube" => Some ( & [ "yt rust" ] ) ,
129- "reddit" => Some ( & [ "red cats" ] ) ,
130- "calculator" => Some ( & [ "= 1+2" , "= history" ] ) ,
131- "unit_convert" => Some ( & [
132- "conv 10 km to mi" ,
133- "conv 1 kwh to j" ,
134- "conv 8 bit to byte" ,
135- "conv 30 mpg to kpl" ,
136- "conv 180 deg to rad" ,
137- ] ) ,
138- "base_convert" => Some ( & [
139- "conv 1010 bin to hex" ,
140- "conv ff hex to bin" ,
141- "conv \" hello\" text to hex" ,
142- "conv 48656c6c6f hex to text" ,
143- "conv 42 dec to bin" ,
144- ] ) ,
145- "clipboard" => Some ( & [ "cb" ] ) ,
146- "bookmarks" => Some ( & [ "bm add https://example.com" , "bm rm" , "bm list" ] ) ,
147- "folders" => Some ( & [ "f add C:/path" , "f rm docs" ] ) ,
148- "shell" => Some ( & [ "sh" , "sh echo hello" ] ) ,
149- "system" => Some ( & [ "sys shutdown" ] ) ,
150- "sysinfo" => Some ( & [ "info" , "info cpu" , "info cpu list 5" ] ) ,
151- "network" => Some ( & [ "net" ] ) ,
152- "weather" => Some ( & [ "weather Berlin" ] ) ,
153- "history" => Some ( & [ "hi" ] ) ,
154- "timer" => Some ( & [
155- "timer add <duration> [name]" ,
156- "timer add 10s tea" ,
157- "timer add 5m" ,
158- "timer add 1:30" ,
159- "durations: s/m/h or hh:mm:ss/mm:ss" ,
160- "alarm <HH:MM> [name]" ,
161- "alarm 07:30 wake up" ,
162- "timer list # show active timers" ,
163- "alarm list # show active alarms" ,
164- "timer pause <id> # pause a timer" ,
165- "timer resume <id> # resume a timer" ,
166- "timer cancel # cancel timers/alarms" ,
167- "timer rm # remove timers" ,
168- ] ) ,
169- "notes" => Some ( & [
170- "note" ,
171- "note add buy milk" ,
172- "note new buy milk" ,
173- "note create buy milk" ,
174- "note list" ,
175- "note rm groceries" ,
176- "notes unused" ,
177- ] ) ,
178- "volume" => Some ( & [ "vol 50" ] ) ,
179- "brightness" => Some ( & [ "bright 50" ] ) ,
180- "asciiart" => Some ( & [ "ascii hello" ] ) ,
181- "screenshot" => Some ( & [
182- "ss" ,
183- "ss clip" ,
184- "Editor: drag to crop, Shift+drag to annotate, use slider to zoom, then Save or Copy" ,
185- ] ) ,
186- "processes" => Some ( & [ "ps" , "ps firefox" ] ) ,
187- "dropcalc" => Some ( & [ "drop 1/128 25" ] ) ,
188- "recycle" => Some ( & [ "rec" ] ) ,
189- "tempfile" => Some ( & [ "tmp new" , "tmp create" ] ) ,
190- "timestamp" => Some ( & [
191- "ts 0" ,
192- "ts 2024-05-01 12:00" ,
193- "tsm 3600000" ,
194- "tsm 01:00:00.500" ,
195- ] ) ,
196- "snippets" => Some ( & [ "cs hello" ] ) ,
197- "favorites" => Some ( & [ "fav add mycmd" , "fav list" ] ) ,
198- "browser_tabs" => Some ( & [ "tab" , "tab cache" ] ) ,
199- "emoji" => Some ( & [ "emoji smile" , "emoji list heart" ] ) ,
200- "ip" => Some ( & [ "ip" , "ip public" ] ) ,
201- "lorem" => Some ( & [ "lorem w 5" , "lorem s 2" ] ) ,
202- "macros" => Some ( & [ "macro list" , "macro mymacro" ] ) ,
203- "omni_search" => Some ( & [ "o list" , "o list docs" ] ) ,
204- "random" => Some ( & [ "rand number 10" , "rand dice" , "rand pw 8" ] ) ,
205- "settings" => Some ( & [ "settings" ] ) ,
206- "stopwatch" => Some ( & [ "sw start" , "sw list" ] ) ,
207- "task_manager" => Some ( & [ "tm" ] ) ,
208- "text_case" => Some ( & [ "case snake Hello World" ] ) ,
209- "todo" => Some ( & [
210- "todo add buy milk @home" ,
211- "todo list" ,
212- "todo list @testing @ui" ,
213- ] ) ,
214- "wikipedia" => Some ( & [ "wiki rust" ] ) ,
215- "help" => Some ( & [ "help" ] ) ,
216- _ => None ,
140+ fn matches_filter (
141+ filter : & str ,
142+ name : & str ,
143+ desc : & str ,
144+ capabilities : & [ String ] ,
145+ commands : & [ Action ] ,
146+ ) -> bool {
147+ if filter. is_empty ( ) {
148+ return true ;
149+ }
150+ let filter = filter. to_lowercase ( ) ;
151+ if name. to_lowercase ( ) . contains ( & filter) || desc. to_lowercase ( ) . contains ( & filter) {
152+ return true ;
153+ }
154+ if capabilities
155+ . iter ( )
156+ . any ( |cap| cap. to_lowercase ( ) . contains ( & filter) )
157+ {
158+ return true ;
159+ }
160+ commands. iter ( ) . any ( |command| {
161+ command. label . to_lowercase ( ) . contains ( & filter)
162+ || command. desc . to_lowercase ( ) . contains ( & filter)
163+ || command. action . to_lowercase ( ) . contains ( & filter)
164+ } )
165+ }
166+
167+ fn command_prefixes ( commands : & [ Action ] ) -> Vec < String > {
168+ let mut prefixes = HashSet :: new ( ) ;
169+ for command in commands {
170+ if let Some ( prefix) = command. label . split_whitespace ( ) . next ( ) {
171+ prefixes. insert ( prefix. to_string ( ) ) ;
172+ }
173+ }
174+ let mut out: Vec < String > = prefixes. into_iter ( ) . collect ( ) ;
175+ out. sort ( ) ;
176+ out
177+ }
178+
179+ fn example_line ( command : & Action ) -> String {
180+ if let Some ( query) = command. action . strip_prefix ( "query:" ) {
181+ query. trim ( ) . to_string ( )
182+ } else {
183+ command. label . clone ( )
217184 }
218185}
0 commit comments