github.com/cloudfoundry/cli@v7.1.0+incompatible/util/ui/prompt.go (about)

     1  package ui
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"io"
     7  	"strconv"
     8  
     9  	"github.com/vito/go-interact/interact"
    10  	"github.com/vito/go-interact/interact/terminal"
    11  )
    12  
    13  const sigIntExitCode = 130
    14  
    15  var ErrInvalidIndex = errors.New("invalid list index")
    16  
    17  type InvalidChoiceError struct {
    18  	Choice string
    19  }
    20  
    21  func (InvalidChoiceError) Error() string {
    22  	return "Some error"
    23  }
    24  
    25  //go:generate counterfeiter . Resolver
    26  
    27  type Resolver interface {
    28  	Resolve(dst interface{}) error
    29  	SetIn(io.Reader)
    30  	SetOut(io.Writer)
    31  }
    32  
    33  // DisplayBoolPrompt outputs the prompt and waits for user input. It only
    34  // allows for a boolean response. A default boolean response can be set with
    35  // defaultResponse.
    36  func (ui *UI) DisplayBoolPrompt(defaultResponse bool, template string, templateValues ...map[string]interface{}) (bool, error) {
    37  	ui.terminalLock.Lock()
    38  	defer ui.terminalLock.Unlock()
    39  
    40  	response := defaultResponse
    41  	interactivePrompt := ui.Interactor.NewInteraction(ui.TranslateText(template, templateValues...))
    42  	interactivePrompt.SetIn(ui.In)
    43  	interactivePrompt.SetOut(ui.OutForInteration)
    44  	err := interactivePrompt.Resolve(&response)
    45  	if isInterrupt(err) {
    46  		ui.Exiter.Exit(sigIntExitCode)
    47  	}
    48  	return response, err
    49  }
    50  
    51  // DisplayOptionalTextPrompt outputs the prompt and waits for user input.
    52  func (ui *UI) DisplayOptionalTextPrompt(defaultValue string, template string, templateValues ...map[string]interface{}) (string, error) {
    53  	interactivePrompt := ui.Interactor.NewInteraction(ui.TranslateText(template, templateValues...))
    54  	var value = defaultValue
    55  	interactivePrompt.SetIn(ui.In)
    56  	interactivePrompt.SetOut(ui.OutForInteration)
    57  	err := interactivePrompt.Resolve(&value)
    58  	if isInterrupt(err) {
    59  		ui.Exiter.Exit(sigIntExitCode)
    60  	}
    61  	return value, err
    62  }
    63  
    64  // DisplayPasswordPrompt outputs the prompt and waits for user input. Hides
    65  // user's response from the screen.
    66  func (ui *UI) DisplayPasswordPrompt(template string, templateValues ...map[string]interface{}) (string, error) {
    67  	ui.terminalLock.Lock()
    68  	defer ui.terminalLock.Unlock()
    69  
    70  	var password interact.Password
    71  	interactivePrompt := ui.Interactor.NewInteraction(ui.TranslateText(template, templateValues...))
    72  	interactivePrompt.SetIn(ui.In)
    73  	interactivePrompt.SetOut(ui.OutForInteration)
    74  	err := interactivePrompt.Resolve(interact.Required(&password))
    75  	if isInterrupt(err) {
    76  		ui.Exiter.Exit(sigIntExitCode)
    77  	}
    78  	return string(password), err
    79  }
    80  
    81  // DisplayTextMenu lets the user choose from a list of options, either by name
    82  // or by number.
    83  func (ui *UI) DisplayTextMenu(choices []string, promptTemplate string, templateValues ...map[string]interface{}) (string, error) {
    84  	for i, c := range choices {
    85  		t := fmt.Sprintf("%d. %s", i+1, c)
    86  		ui.DisplayText(t)
    87  	}
    88  	ui.DisplayNewline()
    89  
    90  	translatedPrompt := ui.TranslateText(promptTemplate, templateValues...)
    91  
    92  	interactivePrompt := ui.Interactor.NewInteraction(translatedPrompt)
    93  
    94  	interactivePrompt.SetIn(ui.In)
    95  	interactivePrompt.SetOut(ui.OutForInteration)
    96  
    97  	var value string = "enter to skip"
    98  	err := interactivePrompt.Resolve(&value)
    99  
   100  	if isInterrupt(err) {
   101  		ui.Exiter.Exit(sigIntExitCode)
   102  	}
   103  
   104  	if err != nil {
   105  		return "", err
   106  	}
   107  
   108  	if value == "enter to skip" {
   109  		return "", nil
   110  	}
   111  
   112  	i, err := strconv.Atoi(value)
   113  	if err != nil {
   114  		if contains(choices, value) {
   115  			return value, nil
   116  		}
   117  		return "", InvalidChoiceError{Choice: value}
   118  	}
   119  
   120  	if i > len(choices) || i <= 0 {
   121  		return "", ErrInvalidIndex
   122  	}
   123  	return choices[i-1], nil
   124  }
   125  
   126  // DisplayTextPrompt outputs the prompt and waits for user input.
   127  func (ui *UI) DisplayTextPrompt(template string, templateValues ...map[string]interface{}) (string, error) {
   128  	interactivePrompt := ui.Interactor.NewInteraction(ui.TranslateText(template, templateValues...))
   129  	var value string
   130  	interactivePrompt.SetIn(ui.In)
   131  	interactivePrompt.SetOut(ui.OutForInteration)
   132  	err := interactivePrompt.Resolve(interact.Required(&value))
   133  	if isInterrupt(err) {
   134  		ui.Exiter.Exit(sigIntExitCode)
   135  	}
   136  	return value, err
   137  }
   138  
   139  func contains(s []string, v string) bool {
   140  	for _, x := range s {
   141  		if x == v {
   142  			return true
   143  		}
   144  	}
   145  	return false
   146  }
   147  
   148  func isInterrupt(err error) bool {
   149  	return err == interact.ErrKeyboardInterrupt || err == terminal.ErrKeyboardInterrupt
   150  }