github.com/jfrog/jfrog-cli-core/v2@v2.51.0/utils/ioutils/promptstrings.go (about) 1 package ioutils 2 3 import ( 4 "bytes" 5 "github.com/jfrog/jfrog-client-go/utils/log" 6 "io" 7 "os" 8 "strings" 9 10 "github.com/chzyer/readline" 11 "github.com/jfrog/jfrog-client-go/utils/errorutils" 12 "github.com/manifoldco/promptui" 13 ) 14 15 // Returns a template for prompt item line 16 func promptItemTemplate() string { 17 // Example: JFrog Artifactory URL (http://localhost:8080/artifactory/) 18 if log.IsColorsSupported() { 19 return " {{ .Option | cyan }}{{if .TargetValue}}({{ .TargetValue }}){{end}}" 20 } 21 return " {{ .Option }}{{if .TargetValue}}({{ .TargetValue }}){{end}}" 22 } 23 24 // Returns a template for selection item line 25 func selectableItemTemplate() string { 26 if log.IsColorsSupported() { 27 return " {{ .Option | cyan }}{{if .DefaultValue}} <{{ .DefaultValue }}>{{end}}" 28 } 29 return " {{ .Option }}{{if .DefaultValue}} <{{ .DefaultValue }}>{{end}}" 30 } 31 32 type PromptItem struct { 33 // The option string to show, i.e - JFrog Artifactory URL. 34 Option string 35 // The variable to set. 36 TargetValue *string 37 // Default value to show. If empty string is entered, use the default value. 38 DefaultValue string 39 } 40 41 // Prompt strings by selecting from list until "Save and continue" is selected. 42 // Usage example: 43 // 🐸 Save and continue 44 // JFrog Artifactory URL (http://localhost:8080/artifactory/) 45 // JFrog Distribution URL () 46 // JFrog Xray URL () 47 // JFrog Mission Control URL () 48 // JFrog Pipelines URL () 49 func PromptStrings(items []PromptItem, label string, onSelect func(PromptItem)) error { 50 items = append([]PromptItem{{Option: "Save and continue"}}, items...) 51 prompt := createSelectableList(len(items), label, promptItemTemplate()) 52 for { 53 prompt.Items = items 54 i, _, err := prompt.Run() 55 if err != nil { 56 return errorutils.CheckError(err) 57 } 58 if i == 0 { 59 return nil 60 } 61 onSelect(items[i]) 62 } 63 } 64 65 func createSelectableList(numOfItems int, label, itemTemplate string) (prompt *promptui.Select) { 66 selectionIcon := "🐸" 67 if !log.IsColorsSupported() { 68 selectionIcon = ">" 69 } 70 templates := &promptui.SelectTemplates{ 71 Label: "{{ . }}", 72 Active: selectionIcon + itemTemplate, 73 Inactive: " " + itemTemplate, 74 } 75 return &promptui.Select{ 76 Label: label, 77 Templates: templates, 78 Stdout: &bellSkipper{}, 79 HideSelected: true, 80 Size: numOfItems, 81 } 82 } 83 84 func SelectString(items []PromptItem, label string, needSearch bool, onSelect func(PromptItem)) error { 85 selectableList := createSelectableList(len(items), label, selectableItemTemplate()) 86 selectableList.Items = items 87 if needSearch { 88 selectableList.StartInSearchMode = true 89 selectableList.Searcher = func(input string, index int) bool { 90 if found := strings.Index(strings.ToLower(items[index].Option), strings.ToLower(input)); found != -1 { 91 return true 92 } 93 return false 94 } 95 } 96 i, _, err := selectableList.Run() 97 if err != nil { 98 return errorutils.CheckError(err) 99 } 100 onSelect(items[i]) 101 return nil 102 } 103 104 // On macOS the terminal's bell is ringing when trying to select items using the up and down arrows. 105 // By using bellSkipper the issue is resolved. 106 type bellSkipper struct{ io.WriteCloser } 107 108 var charBell = []byte{readline.CharBell} 109 110 func (bs *bellSkipper) Write(b []byte) (int, error) { 111 if bytes.Equal(b, charBell) { 112 return 0, nil 113 } 114 return os.Stderr.Write(b) 115 } 116 117 func (bs *bellSkipper) Close() error { 118 return os.Stderr.Close() 119 }