code-intelligence.com/cifuzz@v0.40.0/pkg/dialog/dialog.go (about)

     1  package dialog
     2  
     3  import (
     4  	"os"
     5  	"sort"
     6  	"strings"
     7  
     8  	"atomicgo.dev/keyboard/keys"
     9  	"github.com/pkg/errors"
    10  	"github.com/pterm/pterm"
    11  	"golang.org/x/exp/maps"
    12  
    13  	"code-intelligence.com/cifuzz/internal/config"
    14  	"code-intelligence.com/cifuzz/pkg/log"
    15  )
    16  
    17  // Select offers the user a list of items (label:value) to select from and returns the value of the selected item
    18  func Select(message string, items map[string]string, sorted bool) (string, error) {
    19  	options := maps.Keys(items)
    20  	if sorted {
    21  		sort.Strings(options)
    22  	}
    23  	prompt := pterm.DefaultInteractiveSelect.WithOptions(options)
    24  	prompt.DefaultText = message
    25  
    26  	result, err := prompt.Show()
    27  	if err != nil {
    28  		return "", errors.WithStack(err)
    29  	}
    30  
    31  	return items[result], nil
    32  }
    33  
    34  // MultiSelect offers the user a list of items (label:value) to select from and returns the values of the selected items
    35  func MultiSelect(message string, items map[string]string) ([]string, error) {
    36  	options := maps.Keys(items)
    37  	sort.Strings(options)
    38  
    39  	prompt := pterm.DefaultInteractiveMultiselect.WithOptions(options)
    40  	prompt.DefaultText = message
    41  	prompt.Filter = false
    42  	prompt.KeyConfirm = keys.Enter
    43  	prompt.KeySelect = keys.Space
    44  
    45  	selectedOptions, err := prompt.Show()
    46  	if err != nil {
    47  		return nil, errors.WithStack(err)
    48  	}
    49  	sort.Strings(selectedOptions)
    50  
    51  	var result []string
    52  	for _, option := range selectedOptions {
    53  		result = append(result, items[option])
    54  	}
    55  
    56  	return result, nil
    57  }
    58  
    59  func Confirm(message string, defaultValue bool) (bool, error) {
    60  	var confirmText, rejectText string
    61  	if defaultValue {
    62  		confirmText = "Y"
    63  		rejectText = "n"
    64  	} else {
    65  		confirmText = "y"
    66  		rejectText = "N"
    67  	}
    68  	res, err := pterm.InteractiveConfirmPrinter{
    69  		DefaultValue: defaultValue,
    70  		DefaultText:  message,
    71  		TextStyle:    &pterm.ThemeDefault.PrimaryStyle,
    72  		ConfirmText:  confirmText,
    73  		ConfirmStyle: &pterm.ThemeDefault.PrimaryStyle,
    74  		RejectText:   rejectText,
    75  		RejectStyle:  &pterm.ThemeDefault.PrimaryStyle,
    76  		SuffixStyle:  &pterm.ThemeDefault.SecondaryStyle,
    77  	}.Show()
    78  	return res, errors.WithStack(err)
    79  }
    80  
    81  func Input(message string) (string, error) {
    82  	input := pterm.DefaultInteractiveTextInput.WithDefaultText(message)
    83  	result, err := input.Show()
    84  	if err != nil {
    85  		return "", errors.WithStack(err)
    86  	}
    87  	return result, nil
    88  }
    89  
    90  // ReadSecret reads a secret from the user and prints * characters instead of
    91  // the actual secret.
    92  func ReadSecret(message string) (string, error) {
    93  	secret, err := pterm.DefaultInteractiveTextInput.WithMask("*").Show(message)
    94  	if err != nil {
    95  		return "", errors.WithStack(err)
    96  	}
    97  	return secret, nil
    98  }
    99  
   100  // askToPersistProjectChoice asks the user if they want to persist their
   101  // project choice. If they do, it adds the project to the cifuzz.yaml file.
   102  func AskToPersistProjectChoice(projectName string) error {
   103  	persist, err := Confirm(`Do you want to persist your choice?
   104  This will add a 'project' entry to your cifuzz.yaml.
   105  You can change these values later by editing the file.`, false)
   106  	if err != nil {
   107  		return err
   108  	}
   109  
   110  	if persist {
   111  		project := strings.TrimPrefix(projectName, "projects/")
   112  
   113  		contents, err := os.ReadFile(config.ProjectConfigFile)
   114  		if err != nil {
   115  			return errors.WithStack(err)
   116  		}
   117  		updatedContents := config.EnsureProjectEntry(string(contents), project)
   118  
   119  		err = os.WriteFile(config.ProjectConfigFile, []byte(updatedContents), 0o644)
   120  		if err != nil {
   121  			return errors.WithStack(err)
   122  		}
   123  		log.Notef("Your choice has been persisted in cifuzz.yaml.")
   124  	}
   125  	return nil
   126  }