5
5
"fmt"
6
6
"io"
7
7
"os"
8
+ "strings"
8
9
"text/tabwriter"
9
10
"text/template"
10
11
@@ -18,9 +19,6 @@ import (
18
19
// SelectWithAdd's logic.
19
20
const SelectedAdd = - 1
20
21
21
- // KeyRefresh indicates to refresh the current status
22
- const KeyRefresh = '\x01'
23
-
24
22
// Select represents a list of items used to enable selections, they can be used as search engines, menus
25
23
// or as a list of items in a cli based prompt.
26
24
type Select struct {
@@ -83,6 +81,9 @@ type Select struct {
83
81
84
82
Stdin io.ReadCloser
85
83
Stdout io.WriteCloser
84
+
85
+ // keywords for search
86
+ keywords string
86
87
}
87
88
88
89
// SelectKeys defines the available keys used by select mode to enable the user to move around the list
@@ -171,19 +172,27 @@ type SelectTemplates struct {
171
172
// it shows keys for movement and search.
172
173
Help string
173
174
175
+ // SearchTips is a text/template for displaying search tips while search having results.
176
+ SearchTips string
177
+
178
+ // Keywords is a text/template for the search keywords.
179
+ Keywords string
180
+
174
181
// FuncMap is a map of helper functions that can be used inside of templates according to the text/template
175
182
// documentation.
176
183
//
177
184
// By default, FuncMap contains the color functions used to color the text in templates. If FuncMap
178
185
// is overridden, the colors functions must be added in the override from promptui.FuncMap to work.
179
186
FuncMap template.FuncMap
180
187
181
- label * template.Template
182
- active * template.Template
183
- inactive * template.Template
184
- selected * template.Template
185
- details * template.Template
186
- help * template.Template
188
+ label * template.Template
189
+ active * template.Template
190
+ inactive * template.Template
191
+ selected * template.Template
192
+ details * template.Template
193
+ help * template.Template
194
+ searchTips * template.Template
195
+ keywords * template.Template
187
196
}
188
197
189
198
// SearchPrompt is the prompt displayed in search mode.
@@ -225,6 +234,17 @@ func (s *Select) RunCursorAt(cursorPos, scroll int) (int, string, error) {
225
234
return s .innerRun (cursorPos , scroll , ' ' )
226
235
}
227
236
237
+ func (s * Select ) getKeywords (keywords string ) string {
238
+ keywords = strings .Join (strings .Fields (keywords ), " " )
239
+ if keywords == "" {
240
+ return s .keywords
241
+ }
242
+ if s .keywords == "" {
243
+ return keywords
244
+ }
245
+ return s .keywords + " " + keywords
246
+ }
247
+
228
248
func (s * Select ) innerRun (cursorPos , scroll int , top rune ) (int , string , error ) {
229
249
c := & readline.Config {
230
250
Stdin : s .Stdin ,
@@ -275,7 +295,11 @@ func (s *Select) innerRun(cursorPos, scroll int, top rune) (int, string, error)
275
295
if searchMode {
276
296
searchMode = false
277
297
cur .Replace ("" )
278
- s .list .CancelSearch ()
298
+ if s .keywords == "" {
299
+ s .list .CancelSearch ()
300
+ } else {
301
+ s .list .Search (s .keywords )
302
+ }
279
303
} else {
280
304
searchMode = true
281
305
}
@@ -286,31 +310,49 @@ func (s *Select) innerRun(cursorPos, scroll int, top rune) (int, string, error)
286
310
287
311
cur .Backspace ()
288
312
if len (cur .Get ()) > 0 {
289
- s .list .Search (cur .Get ())
290
- } else {
313
+ s .list .Search (s . getKeywords ( cur .Get () ))
314
+ } else if s . keywords == "" {
291
315
s .list .CancelSearch ()
316
+ } else {
317
+ s .list .Search (s .keywords )
292
318
}
293
319
case key == s .Keys .PageUp .Code || (key == 'h' && ! searchMode ):
294
320
s .list .PageUp ()
295
321
case key == s .Keys .PageDown .Code || (key == 'l' && ! searchMode ):
296
322
s .list .PageDown ()
297
323
case key == KeyRefresh :
298
324
break
325
+ case canSearch && key == KeyCtrlE && (s .keywords != "" || searchMode ):
326
+ s .keywords = ""
327
+ searchMode = false
328
+ cur .Replace ("" )
329
+ s .list .CancelSearch ()
330
+ case canSearch && searchMode && key == KeySoftEnter && s .list .VisibleSize () > 0 :
331
+ s .keywords = s .getKeywords (cur .Get ())
332
+ searchMode = false
333
+ cur .Replace ("" )
299
334
default :
300
335
if canSearch && searchMode {
301
336
cur .Update (string (line ))
302
- s .list .Search (cur .Get ())
337
+ s .list .Search (s . getKeywords ( cur .Get () ))
303
338
}
304
339
}
305
340
306
341
if searchMode {
307
342
header := SearchPrompt + cur .Format ()
343
+ if s .list .VisibleSize () > 0 {
344
+ header += string (render (s .Templates .searchTips , nil ))
345
+ }
308
346
sb .WriteString (header )
309
347
} else if ! s .HideHelp {
310
348
help := s .renderHelp (canSearch )
311
349
sb .Write (help )
312
350
}
313
351
352
+ if s .keywords != "" {
353
+ sb .Write (render (s .Templates .keywords , s .keywords ))
354
+ }
355
+
314
356
label := render (s .Templates .label , s .Label )
315
357
sb .Write (label )
316
358
@@ -421,6 +463,17 @@ func (s *Select) GetCurrentIndex() int {
421
463
return s .list .Index ()
422
464
}
423
465
466
+ // GetVisibleSize returns the size of the current visible items.
467
+ func (s * Select ) GetVisibleSize () int {
468
+ return s .list .VisibleSize ()
469
+ }
470
+
471
+ // GetVisibleItems returns the current visible items.
472
+ func (s * Select ) GetVisibleItems () []interface {} {
473
+ items , _ := s .list .Items ()
474
+ return items
475
+ }
476
+
424
477
func (s * Select ) prepareTemplates () error {
425
478
tpls := s .Templates
426
479
if tpls == nil {
@@ -496,6 +549,24 @@ func (s *Select) prepareTemplates() error {
496
549
497
550
tpls .help = tpl
498
551
552
+ if tpls .SearchTips == "" {
553
+ tpls .SearchTips = `{{ " Enter to lock the search results" | faint }}`
554
+ }
555
+ tpl , err = template .New ("" ).Funcs (tpls .FuncMap ).Parse (tpls .SearchTips )
556
+ if err != nil {
557
+ return err
558
+ }
559
+ tpls .searchTips = tpl
560
+
561
+ if tpls .Keywords == "" {
562
+ tpls .Keywords = `Keywords: {{ . | blue }} {{ " Ctrl+E to erase the search keywords" | faint }}`
563
+ }
564
+ tpl , err = template .New ("" ).Funcs (tpls .FuncMap ).Parse (tpls .Keywords )
565
+ if err != nil {
566
+ return err
567
+ }
568
+ tpls .keywords = tpl
569
+
499
570
s .Templates = tpls
500
571
501
572
return nil
0 commit comments