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  }