Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
August 25, 2021 06:24 pm GMT

Interactive CLI prompts in Go

Tidal Migrations CLI applications

Do you like CLI applications? We love them! At Tidal Migrations we use full-featured GUI IDEs and editors like VS Code and Emacs but also vim and git running in our terminals. Every day we use bash, awk, sed and lots of other CLI tools and apps for work and fun. Also, we like to develop CLI apps and with this post, we're going to show you how to implement different interactive prompts for your CLI apps written in Go.

Passing data to CLI apps

Oftentimes CLI applications don't just work by themselves, but some process or operation is required on the information or data.

There are different ways to pass data to command line applications. Using flags, environment variables, file names as CLI arguments or reading from standard input is quite common and is pretty easy to implement using just the standard Go library. Using interactive prompts can spice up your CLI application and improve the overall UX.

Let's get started!

How to implement text input prompt

The basic text input prompt is easy to implement. Just read from standard input until the new line character (
):

package mainimport (    "bufio"    "fmt"    "os"    "strings")// StringPrompt asks for a string value using the labelfunc StringPrompt(label string) string {    var s string    r := bufio.NewReader(os.Stdin)    for {        fmt.Fprint(os.Stderr, label+" ")        s, _ = r.ReadString('
'
) if s != "" { break } } return strings.TrimSpace(s)}func main() { name := StringPrompt("What is your name?") fmt.Printf("Hello, %s!
", name)}

How to implement password input prompt

Password prompts are similar to text input prompts, except the user's typed input should be hidden:

package mainimport (    "fmt"    "os"    "syscall"    "golang.org/x/term")// PasswordPrompt asks for a string value using the label.// The entered value will not be displayed on the screen// while typing.func PasswordPrompt(label string) string {    var s string    for {        fmt.Fprint(os.Stderr, label+" ")        b, _ := term.ReadPassword(int(syscall.Stdin))        s = string(b)        if s != "" {            break        }    }    fmt.Println()    return s}func main() {    password := PasswordPrompt("What is your password?")    fmt.Printf("Oh, I see! Your password is %q
", password)}

How to implement Yes/No prompt

For Yes/No prompts we're going to create an infinite loop to keep asking until the user answers yes or no:

package mainimport (    "bufio"    "fmt"    "os"    "strings")// YesNoPrompt asks yes/no questions using the label.func YesNoPrompt(label string, def bool) bool {    choices := "Y/n"    if !def {        choices = "y/N"    }    r := bufio.NewReader(os.Stdin)    var s string    for {        fmt.Fprintf(os.Stderr, "%s (%s) ", label, choices)        s, _ = r.ReadString('
'
) s = strings.TrimSpace(s) if s == "" { return def } s = strings.ToLower(s) if s == "y" || s == "yes" { return true } if s == "n" || s == "no" { return false } }}func main() { ok := YesNoPrompt("Dev.to is awesome!", true) if ok { fmt.Println("Agree!") } else { fmt.Println("Huh?") }}

How to implement interactive checkboxes

To create an interactive multi-select prompt we're going to use an awesome survey package:

package mainimport (    "fmt"    "strings"    "github.com/AlecAivazis/survey/v2")func Checkboxes(label string, opts []string) []string {    res := []string{}    prompt := &survey.MultiSelect{        Message: label,        Options: opts,    }    survey.AskOne(prompt, &res)    return res}func main() {    answers := Checkboxes(        "Which are your favourite programming languages?",        []string{            "C",            "Python",            "Java",            "C++",            "C#",            "Visual Basic",            "JavaScript",            "PHP",            "Assembly Language",            "SQL",            "Groovy",            "Classic Visual Basic",            "Fortran",            "R",            "Ruby",            "Swift",            "MATLAB",            "Go",            "Prolog",            "Perl",        },    )    s := strings.Join(answers, ", ")    fmt.Println("Oh, I see! You like", s)}

Caveats and workarounds

If you pipe some input data to your interactive CLI app, the prompts will read that data:

$ echo "Petr" | go run main.goWhat is your name? Hello, Petr!

Sometimes such behavior is acceptable, but sometimes not. To check if the terminal is interactive let's use term.IsTerminal function:

package mainimport (    "fmt"    "syscall"    "golang.org/x/term")func main() {    if term.IsTerminal(int(syscall.Stdin)) {        fmt.Println("Terminal is interactive! You're good to use prompts!")    } else {        fmt.Println("Terminal is not interactive! Consider using flags or environment variables!")    }}
$ echo "Hello" | go run main.goTerminal is not interactive! Consider using flags or environment variables!$ go run main.goTerminal is interactive! You're good to use prompts!

Libraries

As you can see, it's pretty easy to implement basic interactive prompts, but for complex ones it's better to use some Go packages from the community:

GitHub logo AlecAivazis / survey

A golang library for building interactive and accessible prompts with full support for windows and posix terminals.

Survey

Build StatusGoDoc

A library for building interactive and accessible prompts on terminals supporting ANSI escape sequences.

package mainimport (    "fmt"    "github.com/AlecAivazis/survey/v2")// the questions to askvar qs = []*survey.Question{    {        Name:     "name",        Prompt:   &survey.Input{Message: "What is your name?"},        Validate: survey.Required,        Transform: survey.Title,    },    {        Name: "color",        Prompt: &survey.Select{            Message: "Choose a color:",            Options: []string{"red", "blue", "green"},            Default: "red",        },    },    {        Name: "age",        Prompt:   &survey.Input{Message: "How old are you?"},    },}func main() {    // the answers will be written to this struct    answers := struct {        Name          string                  // survey will match the question and field names        FavoriteColor string

GitHub logo Songmu / prompter

golang utility for easy prompting

prompter

Test StatusCoverage StatusMIT LicenseGoDev

Description

utility for easy prompting in Golang

Synopsis

twitterID := prompter.Prompt("Enter your twitter ID", "")lang := prompter.Choose("Which language do you like the most?", []string{"Perl", "Golang", "Scala", "Ruby"}, "Perl")passwd := prompter.Password("Enter your password")var likeSushi bool = prompter.YN("Do you like sushi?", true)var likeBeer bool = prompter.YesNo("Do you like beer?", false)

Features

  • Easy to use
  • Care non-interactive (not a tty) environment
    • Default is used and the process is not blocked
  • No howeyc/gopass (which uses cgo) dependency
    • cross build friendly
  • Customizable prompt setting by using &prompter.Prompter{} directly

License

MIT

Author

Songmu

GitHub logo manifoldco / promptui

Interactive prompt for command-line applications

promptui

Interactive prompt for command-line applications.

We built Promptui because we wanted to make it easy and fun to explore cloudservices with manifold cli.

Code of Conduct |Contribution Guidelines

GitHub releaseGoDocTravisGo Report CardLicense

Overview

promptui

Promptui is a library providing a simple interface to create command-lineprompts for go. It can be easily integrated intospf13/cobraurfave/cli or any cli go application.

Promptui has two main input modes:

  • Prompt provides a single line for user input. Prompt supportsoptional live validation, confirmation and masking the input.

  • Select provides a list of options to choose from. Select supportspagination, search, detailed view and custom templates.

For a full list of options check GoDoc.

Basic Usage

Prompt

package mainimport (    "errors"    "fmt"    "strconv"    "github.com/manifoldco/promptui")func main() {    validate := func(input string) error {        _, err := strconv.ParseFloat(input, 64)        if

Conclusion

That's it! We hope you liked it! Code examples are available on GitHub.

If you're interested in CLI applications development in Go and we Tidal Migrations are hiring! Please check our Careers page!

Long live the command line!


Original Link: https://dev.to/tidalmigrations/interactive-cli-prompts-in-go-3bj9

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To