Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitd15c470

Browse files
stirbyjohnstcnjoobisb
authored
chore: add cherry-picks for patch 2.18.2 (#16061)
Co-authored-by: Cian Johnston <cian@coder.com>Co-authored-by: Joobi S B <joobisb@gmail.com>
1 parent765d99c commitd15c470

File tree

11 files changed

+854
-175
lines changed

11 files changed

+854
-175
lines changed

‎cli/cliui/select.go

Lines changed: 132 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -300,9 +300,10 @@ func (m selectModel) filteredOptions() []string {
300300
}
301301

302302
typeMultiSelectOptionsstruct {
303-
Messagestring
304-
Options []string
305-
Defaults []string
303+
Messagestring
304+
Options []string
305+
Defaults []string
306+
EnableCustomInputbool
306307
}
307308

308309
funcMultiSelect(inv*serpent.Invocation,optsMultiSelectOptions) ([]string,error) {
@@ -328,9 +329,10 @@ func MultiSelect(inv *serpent.Invocation, opts MultiSelectOptions) ([]string, er
328329
}
329330

330331
initialModel:=multiSelectModel{
331-
search:textinput.New(),
332-
options:options,
333-
message:opts.Message,
332+
search:textinput.New(),
333+
options:options,
334+
message:opts.Message,
335+
enableCustomInput:opts.EnableCustomInput,
334336
}
335337

336338
initialModel.search.Prompt=""
@@ -370,12 +372,15 @@ type multiSelectOption struct {
370372
}
371373

372374
typemultiSelectModelstruct {
373-
search textinput.Model
374-
options []*multiSelectOption
375-
cursorint
376-
messagestring
377-
canceledbool
378-
selectedbool
375+
search textinput.Model
376+
options []*multiSelectOption
377+
cursorint
378+
messagestring
379+
canceledbool
380+
selectedbool
381+
isCustomInputModebool// track if we're adding a custom option
382+
customInputstring// store custom input
383+
enableCustomInputbool// control whether custom input is allowed
379384
}
380385

381386
func (multiSelectModel)Init() tea.Cmd {
@@ -386,6 +391,10 @@ func (multiSelectModel) Init() tea.Cmd {
386391
func (mmultiSelectModel)Update(msg tea.Msg) (tea.Model, tea.Cmd) {
387392
varcmd tea.Cmd
388393

394+
ifm.isCustomInputMode {
395+
returnm.handleCustomInputMode(msg)
396+
}
397+
389398
switchmsg:=msg.(type) {
390399
caseterminateMsg:
391400
m.canceled=true
@@ -398,6 +407,11 @@ func (m multiSelectModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
398407
returnm,tea.Quit
399408

400409
casetea.KeyEnter:
410+
// Switch to custom input mode if we're on the "+ Add custom value:" option
411+
ifm.enableCustomInput&&m.cursor==len(m.filteredOptions()) {
412+
m.isCustomInputMode=true
413+
returnm,nil
414+
}
401415
iflen(m.options)!=0 {
402416
m.selected=true
403417
returnm,tea.Quit
@@ -413,16 +427,16 @@ func (m multiSelectModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
413427
returnm,nil
414428

415429
casetea.KeyUp:
416-
options:=m.filteredOptions()
430+
maxIndex:=m.getMaxIndex()
417431
ifm.cursor>0 {
418432
m.cursor--
419433
}else {
420-
m.cursor=len(options)-1
434+
m.cursor=maxIndex
421435
}
422436

423437
casetea.KeyDown:
424-
options:=m.filteredOptions()
425-
ifm.cursor<len(options)-1 {
438+
maxIndex:=m.getMaxIndex()
439+
ifm.cursor<maxIndex {
426440
m.cursor++
427441
}else {
428442
m.cursor=0
@@ -457,6 +471,91 @@ func (m multiSelectModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
457471
returnm,cmd
458472
}
459473

474+
func (mmultiSelectModel)getMaxIndex()int {
475+
options:=m.filteredOptions()
476+
ifm.enableCustomInput {
477+
// Include the "+ Add custom value" entry
478+
returnlen(options)
479+
}
480+
// Includes only the actual options
481+
returnlen(options)-1
482+
}
483+
484+
// handleCustomInputMode manages keyboard interactions when in custom input mode
485+
func (m*multiSelectModel)handleCustomInputMode(msg tea.Msg) (tea.Model, tea.Cmd) {
486+
keyMsg,ok:=msg.(tea.KeyMsg)
487+
if!ok {
488+
returnm,nil
489+
}
490+
491+
switchkeyMsg.Type {
492+
casetea.KeyEnter:
493+
returnm.handleCustomInputSubmission()
494+
495+
casetea.KeyCtrlC:
496+
m.canceled=true
497+
returnm,tea.Quit
498+
499+
casetea.KeyBackspace:
500+
returnm.handleCustomInputBackspace()
501+
502+
default:
503+
m.customInput+=keyMsg.String()
504+
returnm,nil
505+
}
506+
}
507+
508+
// handleCustomInputSubmission processes the submission of custom input
509+
func (m*multiSelectModel)handleCustomInputSubmission() (tea.Model, tea.Cmd) {
510+
ifm.customInput=="" {
511+
m.isCustomInputMode=false
512+
returnm,nil
513+
}
514+
515+
// Clear search to ensure option is visible and cursor points to the new option
516+
m.search.SetValue("")
517+
518+
// Check for duplicates
519+
fori,opt:=rangem.options {
520+
ifopt.option==m.customInput {
521+
// If the option exists but isn't chosen, select it
522+
if!opt.chosen {
523+
opt.chosen=true
524+
}
525+
526+
// Point cursor to the new option
527+
m.cursor=i
528+
529+
// Reset custom input mode to disabled
530+
m.isCustomInputMode=false
531+
m.customInput=""
532+
returnm,nil
533+
}
534+
}
535+
536+
// Add new unique option
537+
m.options=append(m.options,&multiSelectOption{
538+
option:m.customInput,
539+
chosen:true,
540+
})
541+
542+
// Point cursor to the newly added option
543+
m.cursor=len(m.options)-1
544+
545+
// Reset custom input mode to disabled
546+
m.customInput=""
547+
m.isCustomInputMode=false
548+
returnm,nil
549+
}
550+
551+
// handleCustomInputBackspace handles backspace in custom input mode
552+
func (m*multiSelectModel)handleCustomInputBackspace() (tea.Model, tea.Cmd) {
553+
iflen(m.customInput)>0 {
554+
m.customInput=m.customInput[:len(m.customInput)-1]
555+
}
556+
returnm,nil
557+
}
558+
460559
func (mmultiSelectModel)View()string {
461560
vars strings.Builder
462561

@@ -469,13 +568,19 @@ func (m multiSelectModel) View() string {
469568
returns.String()
470569
}
471570

571+
ifm.isCustomInputMode {
572+
_,_=s.WriteString(fmt.Sprintf("%s\nEnter custom value: %s\n",msg,m.customInput))
573+
returns.String()
574+
}
575+
472576
_,_=s.WriteString(fmt.Sprintf(
473577
"%s %s[Use arrows to move, space to select, <right> to all, <left> to none, type to filter]\n",
474578
msg,
475579
m.search.View(),
476580
))
477581

478-
fori,option:=rangem.filteredOptions() {
582+
options:=m.filteredOptions()
583+
fori,option:=rangeoptions {
479584
cursor:=" "
480585
chosen:="[ ]"
481586
o:=option.option
@@ -498,6 +603,16 @@ func (m multiSelectModel) View() string {
498603
))
499604
}
500605

606+
ifm.enableCustomInput {
607+
// Add the "+ Add custom value" option at the bottom
608+
cursor:=" "
609+
text:=" + Add custom value"
610+
ifm.cursor==len(options) {
611+
cursor=pretty.Sprint(DefaultStyles.Keyword,"> ")
612+
text=pretty.Sprint(DefaultStyles.Keyword,text)
613+
}
614+
_,_=s.WriteString(fmt.Sprintf("%s%s\n",cursor,text))
615+
}
501616
returns.String()
502617
}
503618

‎cli/cliui/select_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,39 @@ func TestMultiSelect(t *testing.T) {
101101
}()
102102
require.Equal(t,items,<-msgChan)
103103
})
104+
105+
t.Run("MultiSelectWithCustomInput",func(t*testing.T) {
106+
t.Parallel()
107+
items:= []string{"Code","Chairs","Whale","Diamond","Carrot"}
108+
ptty:=ptytest.New(t)
109+
msgChan:=make(chan []string)
110+
gofunc() {
111+
resp,err:=newMultiSelectWithCustomInput(ptty,items)
112+
assert.NoError(t,err)
113+
msgChan<-resp
114+
}()
115+
require.Equal(t,items,<-msgChan)
116+
})
117+
}
118+
119+
funcnewMultiSelectWithCustomInput(ptty*ptytest.PTY,items []string) ([]string,error) {
120+
varvalues []string
121+
cmd:=&serpent.Command{
122+
Handler:func(inv*serpent.Invocation)error {
123+
selectedItems,err:=cliui.MultiSelect(inv, cliui.MultiSelectOptions{
124+
Options:items,
125+
Defaults:items,
126+
EnableCustomInput:true,
127+
})
128+
iferr==nil {
129+
values=selectedItems
130+
}
131+
returnerr
132+
},
133+
}
134+
inv:=cmd.Invoke()
135+
ptty.Attach(inv)
136+
returnvalues,inv.Run()
104137
}
105138

106139
funcnewMultiSelect(ptty*ptytest.PTY,items []string) ([]string,error) {

‎cli/prompts.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,15 @@ func (RootCmd) promptExample() *serpent.Command {
4141
Default:"",
4242
Value:serpent.StringArrayOf(&multiSelectValues),
4343
}
44+
45+
enableCustomInputbool
46+
enableCustomInputOption= serpent.Option{
47+
Name:"enable-custom-input",
48+
Description:"Enable custom input option in multi-select.",
49+
Required:false,
50+
Flag:"enable-custom-input",
51+
Value:serpent.BoolOf(&enableCustomInput),
52+
}
4453
)
4554
cmd:=&serpent.Command{
4655
Use:"prompt-example",
@@ -156,14 +165,15 @@ func (RootCmd) promptExample() *serpent.Command {
156165
multiSelectValues,multiSelectError=cliui.MultiSelect(inv, cliui.MultiSelectOptions{
157166
Message:"Select some things:",
158167
Options: []string{
159-
"Code","Chair","Whale","Diamond","Carrot",
168+
"Code","Chairs","Whale","Diamond","Carrot",
160169
},
161-
Defaults: []string{"Code"},
170+
Defaults: []string{"Code"},
171+
EnableCustomInput:enableCustomInput,
162172
})
163173
}
164174
_,_=fmt.Fprintf(inv.Stdout,"%q are nice choices.\n",strings.Join(multiSelectValues,", "))
165175
returnmultiSelectError
166-
},useThingsOption),
176+
},useThingsOption,enableCustomInputOption),
167177
promptCmd("rich-parameter",func(inv*serpent.Invocation)error {
168178
value,err:=cliui.RichSelect(inv, cliui.RichSelectOptions{
169179
Options: []codersdk.TemplateVersionParameterOption{

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp