@@ -10,6 +10,7 @@ import (
10
10
"golang.org/x/xerrors"
11
11
12
12
"github.com/coder/coder/v2/codersdk"
13
+ "github.com/coder/pretty"
13
14
"github.com/coder/serpent"
14
15
)
15
16
@@ -80,6 +81,7 @@ func Select(inv *serpent.Invocation, opts SelectOptions) (string, error) {
80
81
hideSearch : opts .HideSearch ,
81
82
options : opts .Options ,
82
83
height : opts .Size ,
84
+ message : opts .Message ,
83
85
}
84
86
85
87
if initialModel .height == 0 {
@@ -110,6 +112,7 @@ type selectModel struct {
110
112
options []string
111
113
cursor int
112
114
height int
115
+ message string
113
116
selected string
114
117
canceled bool
115
118
hideSearch bool
@@ -170,22 +173,33 @@ func (m selectModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
170
173
func (m selectModel ) View () string {
171
174
var s string
172
175
173
- if m .hideSearch {
174
- s += "? [Use arrows to move]\n "
175
- } else {
176
- s += fmt .Sprintf ("? %s [Use arrows to move, type to filter]\n " , m .search .View ())
177
- }
176
+ msg := pretty .Sprintf (pretty .Bold (), "? %s" , m .message )
178
177
179
- options , start := m .viewableOptions ()
180
-
181
- for i , option := range options {
182
- // Is this the currently selected option?
183
- cursor := " "
184
- if m .cursor == start + i {
185
- cursor = ">"
178
+ if m .selected == "" {
179
+ if m .hideSearch {
180
+ s += fmt .Sprintf ("%s [Use arrows to move]\n " , msg )
181
+ } else {
182
+ s += fmt .Sprintf ("%s %s[Use arrows to move, type to filter]\n " , msg , m .search .View ())
186
183
}
187
184
188
- s += fmt .Sprintf ("%s %s\n " , cursor , option )
185
+ options , start := m .viewableOptions ()
186
+
187
+ for i , option := range options {
188
+ // Is this the currently selected option?
189
+ style := pretty .Wrap (" " , "" )
190
+ if m .cursor == start + i {
191
+ style = pretty.Style {
192
+ pretty .Wrap ("> " , "" ),
193
+ pretty .FgColor (Green ),
194
+ }
195
+ }
196
+
197
+ s += pretty .Sprint (style , option )
198
+ s += "\n "
199
+ }
200
+ } else {
201
+ selected := pretty .Sprint (DefaultStyles .Keyword , m .selected )
202
+ s += fmt .Sprintf ("%s %s\n " , msg , selected )
189
203
}
190
204
191
205
return s
@@ -238,11 +252,18 @@ func MultiSelect(inv *serpent.Invocation, opts MultiSelectOptions) ([]string, er
238
252
options := make ([]multiSelectOption , len (opts .Options ))
239
253
for i , option := range opts .Options {
240
254
options [i ].option = option
255
+
256
+ for _ , d := range opts .Defaults {
257
+ if option == d {
258
+ options [i ].chosen = true
259
+ }
260
+ }
241
261
}
242
262
243
263
initialModel := multiSelectModel {
244
264
search : textinput .New (),
245
265
options : options ,
266
+ message : opts .Message ,
246
267
}
247
268
248
269
initialModel .search .Prompt = ""
@@ -278,7 +299,9 @@ type multiSelectModel struct {
278
299
search textinput.Model
279
300
options []multiSelectOption
280
301
cursor int
302
+ message string
281
303
canceled bool
304
+ selected bool
282
305
}
283
306
284
307
func (multiSelectModel ) Init () tea.Cmd {
@@ -297,12 +320,13 @@ func (m multiSelectModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
297
320
298
321
case tea .KeyEnter :
299
322
if len (m .options ) != 0 {
323
+ m .selected = true
300
324
return m , tea .Quit
301
325
}
302
326
303
327
case tea .KeySpace :
304
328
if len (m .options ) != 0 {
305
- m .options [m .cursor ].chosen = true
329
+ m .options [m .cursor ].chosen = ! m . options [ m . cursor ]. chosen
306
330
}
307
331
308
332
case tea .KeyUp :
@@ -343,21 +367,46 @@ func (m multiSelectModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
343
367
}
344
368
345
369
func (m multiSelectModel ) View () string {
346
- s := fmt . Sprintf ( "? %s [Use arrows to move, space to select, <right> to all, <left> to none, type to filter] \n " , m . search . View ())
370
+ var s string
347
371
348
- for i , option := range m .options {
349
- cursor := " "
350
- if m .cursor == i {
351
- cursor = ">"
352
- }
372
+ msg := pretty .Sprintf (pretty .Bold (), "? %s" , m .message )
353
373
354
- chosen := "[ ]"
355
- if option .chosen {
356
- chosen = "[x]"
374
+ if ! m .selected {
375
+ s += fmt .Sprintf ("%s %s[Use arrows to move, space to select, <right> to all, <left> to none, type to filter]\n " , msg , m .search .View ())
376
+
377
+ for i , option := range m .options {
378
+ cursor := " "
379
+ if m .cursor == i {
380
+ cursor = pretty .Sprint (pretty .FgColor (Green ), "> " )
381
+ }
382
+
383
+ chosen := "[ ]"
384
+ if option .chosen {
385
+ chosen = pretty .Sprint (pretty .FgColor (Green ), "[x]" )
386
+ }
387
+
388
+ o := option .option
389
+ if m .cursor == i {
390
+ o = pretty .Sprint (pretty .FgColor (Green ), o )
391
+ }
392
+
393
+ s += fmt .Sprintf ("%s%s %s\n " , cursor , chosen , o )
357
394
}
395
+ } else {
396
+ selected := pretty .Sprint (DefaultStyles .Keyword , strings .Join (m .SelectedOptions (), ", " ))
358
397
359
- s += fmt .Sprintf ("%s %s %s \n " , cursor , chosen , option . option )
398
+ s += fmt .Sprintf ("%s %s\n " , msg , selected )
360
399
}
361
400
362
401
return s
363
402
}
403
+
404
+ func (m multiSelectModel ) SelectedOptions () []string {
405
+ selected := []string {}
406
+ for _ , o := range m .options {
407
+ if o .chosen {
408
+ selected = append (selected , o .option )
409
+ }
410
+ }
411
+ return selected
412
+ }
0 commit comments