diff options
Diffstat (limited to 'input/prompt.go')
-rw-r--r-- | input/prompt.go | 138 |
1 files changed, 134 insertions, 4 deletions
diff --git a/input/prompt.go b/input/prompt.go index 960ecd62..12aa7b92 100644 --- a/input/prompt.go +++ b/input/prompt.go @@ -3,13 +3,18 @@ package input import ( "bufio" "fmt" + "net/url" "os" + "sort" "strconv" "strings" "syscall" + "time" "golang.org/x/crypto/ssh/terminal" + "github.com/MichaelMure/git-bug/bridge/core/auth" + "github.com/MichaelMure/git-bug/util/colors" "github.com/MichaelMure/git-bug/util/interrupt" ) @@ -26,11 +31,29 @@ func Required(name string, value string) (string, error) { return "", nil } +// IsURL is a validator checking that the value is a fully formed URL +func IsURL(name string, value string) (string, error) { + u, err := url.Parse(value) + if err != nil { + return fmt.Sprintf("%s is invalid: %v", name, err), nil + } + if u.Scheme == "" { + return fmt.Sprintf("%s is missing a scheme", name), nil + } + if u.Host == "" { + return fmt.Sprintf("%s is missing a host", name), nil + } + return "", nil +} + +// Prompts + func Prompt(prompt, name string, validators ...PromptValidator) (string, error) { return PromptDefault(prompt, name, "", validators...) } func PromptDefault(prompt, name, preValue string, validators ...PromptValidator) (string, error) { +loop: for { if preValue != "" { _, _ = fmt.Fprintf(os.Stderr, "%s [%s]: ", prompt, preValue) @@ -56,7 +79,7 @@ func PromptDefault(prompt, name, preValue string, validators ...PromptValidator) } if complaint != "" { _, _ = fmt.Fprintln(os.Stderr, complaint) - continue + continue loop } } @@ -75,6 +98,7 @@ func PromptPassword(prompt, name string, validators ...PromptValidator) (string, }) defer cancel() +loop: for { _, _ = fmt.Fprintf(os.Stderr, "%s: ", prompt) @@ -96,7 +120,7 @@ func PromptPassword(prompt, name string, validators ...PromptValidator) (string, } if complaint != "" { _, _ = fmt.Fprintln(os.Stderr, complaint) - continue + continue loop } } @@ -121,10 +145,116 @@ func PromptChoice(prompt string, choices []string) (int, error) { index, err := strconv.Atoi(line) if err != nil || index < 1 || index > len(choices) { - fmt.Println("invalid input") + _, _ = fmt.Fprintln(os.Stderr, "invalid input") + continue + } + + return index - 1, nil + } +} + +func PromptURLWithRemote(prompt, name string, validRemotes []string, validators ...PromptValidator) (string, error) { + if len(validRemotes) == 0 { + return Prompt(prompt, name, validators...) + } + + sort.Strings(validRemotes) + + for { + _, _ = fmt.Fprintln(os.Stderr, "\nDetected projects:") + + for i, remote := range validRemotes { + _, _ = fmt.Fprintf(os.Stderr, "[%d]: %v\n", i+1, remote) + } + + _, _ = fmt.Fprintf(os.Stderr, "\n[0]: Another project\n\n") + _, _ = fmt.Fprintf(os.Stderr, "Select option: ") + + line, err := bufio.NewReader(os.Stdin).ReadString('\n') + if err != nil { + return "", err + } + + line = strings.TrimSpace(line) + + index, err := strconv.Atoi(line) + if err != nil || index < 0 || index > len(validRemotes) { + _, _ = fmt.Fprintln(os.Stderr, "invalid input") + continue + } + + // if user want to enter another project url break this loop + if index == 0 { + break + } + + return validRemotes[index-1], nil + } + + return Prompt(prompt, name, validators...) +} + +func PromptCredential(target, name string, credentials []auth.Credential, choices []string) (auth.Credential, int, error) { + if len(credentials) == 0 && len(choices) == 0 { + return nil, 0, fmt.Errorf("no possible choice") + } + if len(credentials) == 0 && len(choices) == 1 { + return nil, 0, nil + } + + sort.Sort(auth.ById(credentials)) + + for { + _, _ = fmt.Fprintln(os.Stderr) + + offset := 0 + for i, choice := range choices { + _, _ = fmt.Fprintf(os.Stderr, "[%d]: %s\n", i+1, choice) + offset++ + } + + if len(credentials) > 0 { + _, _ = fmt.Fprintln(os.Stderr) + _, _ = fmt.Fprintf(os.Stderr, "Existing %s for %s:\n", name, target) + + for i, cred := range credentials { + meta := make([]string, 0, len(cred.Metadata())) + for k, v := range cred.Metadata() { + meta = append(meta, k+":"+v) + } + sort.Strings(meta) + metaFmt := strings.Join(meta, ",") + + fmt.Printf("[%d]: %s => (%s) (%s)\n", + i+1+offset, + colors.Cyan(cred.ID().Human()), + metaFmt, + cred.CreateTime().Format(time.RFC822), + ) + } + } + + _, _ = fmt.Fprintln(os.Stderr) + _, _ = fmt.Fprintf(os.Stderr, "Select option: ") + + line, err := bufio.NewReader(os.Stdin).ReadString('\n') + _, _ = fmt.Fprintln(os.Stderr) + if err != nil { + return nil, 0, err + } + + line = strings.TrimSpace(line) + index, err := strconv.Atoi(line) + if err != nil || index < 1 || index > len(choices)+len(credentials) { + _, _ = fmt.Fprintln(os.Stderr, "invalid input") continue } - return index, nil + switch { + case index <= len(choices): + return nil, index - 1, nil + default: + return credentials[index-len(choices)-1], 0, nil + } } } |