prompt.go

 1package input
 2
 3import (
 4	"bufio"
 5	"fmt"
 6	"os"
 7	"strings"
 8	"syscall"
 9
10	"github.com/MichaelMure/git-bug/util/interrupt"
11	"golang.org/x/crypto/ssh/terminal"
12)
13
14func PromptValue(name string, preValue string) (string, error) {
15	return promptValue(name, preValue, false)
16}
17
18func PromptValueRequired(name string, preValue string) (string, error) {
19	return promptValue(name, preValue, true)
20}
21
22func promptValue(name string, preValue string, required bool) (string, error) {
23	for {
24		if preValue != "" {
25			_, _ = fmt.Fprintf(os.Stderr, "%s [%s]: ", name, preValue)
26		} else {
27			_, _ = fmt.Fprintf(os.Stderr, "%s: ", name)
28		}
29
30		line, err := bufio.NewReader(os.Stdin).ReadString('\n')
31		if err != nil {
32			return "", err
33		}
34
35		line = strings.TrimSpace(line)
36
37		if preValue != "" && line == "" {
38			return preValue, nil
39		}
40
41		if required && line == "" {
42			_, _ = fmt.Fprintf(os.Stderr, "%s is empty\n", name)
43			continue
44		}
45
46		return line, nil
47	}
48}
49
50// PromptPassword performs interactive input collection to get the user password
51// while halting echo on the controlling terminal.
52func PromptPassword() (string, error) {
53	termState, err := terminal.GetState(int(syscall.Stdin))
54	if err != nil {
55		return "", err
56	}
57
58	cancel := interrupt.RegisterCleaner(func() error {
59		return terminal.Restore(int(syscall.Stdin), termState)
60	})
61	defer cancel()
62
63	for {
64		fmt.Print("password: ")
65		bytePassword, err := terminal.ReadPassword(int(syscall.Stdin))
66		// new line for coherent formatting, ReadPassword clip the normal new line
67		// entered by the user
68		fmt.Println()
69
70		if err != nil {
71			return "", err
72		}
73
74		if len(bytePassword) > 0 {
75			return string(bytePassword), nil
76		}
77
78		fmt.Println("password is empty")
79	}
80}