Golang prompt - Create interactive CLI prompt in GO


GO

Author: Tuan Nguyen
Reviewer: Deepak Prasad

We often use CLI tools and commands like bash, awk, sed, and many others for both business and play. Additionally, we enjoy creating CLI apps, therefore in this post, we'll demonstrate how to add various interactive prompts to your Go-based CLI apps. Sometimes, we want to pass data to CLI apps. It is relatively common and rather simple to build using just the standard Go library to use flags, environment variables, file names, or reading from standard input. You may spice up your CLI application and enhance the user experience by using interactive prompts.

 

Simple text input prompt in Golang

In the previous article, we walked through a basic text input prompt. Just read till we reach the next line character (\n) in standard input:

package main

import (
    "bufio"
    "fmt"
    "os"
    "strings"
)

// InputPrompt receives a string value using the label
func InputPrompt(label string) string {
    var s string
    r := bufio.NewReader(os.Stdin)
    for {
        fmt.Fprint(os.Stderr, label+" ")
        s, _ = r.ReadString('\n')
        if s != "" {
            break
        }
    }
    return strings.TrimSpace(s)
}

func main() {
    message := InputPrompt("Enter your message:")
    fmt.Printf("Your message: %s!\n", message)
}

Output:

Enter your message: Hello GoLinuxCloud members!
Your message: Hello GoLinuxCloud members!!

 

Hidden password input prompt

Password prompts are similar to input prompts, except the user's written input ought to be hidden. We can use term package to achieve this purpose. First you have to install term package by this command:

go get -u golang.org/x/term

Here is an example of reading password from console using ReadPassword() function:

func ReadPassword(fd int) ([]byte, error): ReadPassword reads a line of input from a terminal without local echo. This is commonly used for inputting passwords and other sensitive data. The slice returned does not include the \n.

package main

import (
	"fmt"
	"os"
	"syscall"

	"golang.org/x/term"
)

// The entered password will not be displayed on the screen
func SensitivePrompt(label string) string {
	var s string
	for {
		fmt.Fprint(os.Stderr, label+" ")
		pw, _ := term.ReadPassword(int(syscall.Stdin))
		s = string(pw)
		if s != "" {
			break
		}
	}
	fmt.Println()
	return s
}

func main() {
	sensitiveString := SensitivePrompt("Enter your password:")
	fmt.Printf("Your password is %q\n", sensitiveString)
}

Output:

Enter your password:
Your password is "HelloPass0rd"

 

Perform input validation and formatting with promptui

Promptui is a library providing a simple interface to create command-line prompts for go. Prompt() function provides a single line for user input. Prompt supports optional live validation, confirmation and masking the input. In the below example, we will see how to validate the input with Prompt() function:

package main

import (
	"errors"
	"fmt"
	"strconv"

	"github.com/manifoldco/promptui"
)

func main() {
	// validate the input
	validate := func(input string) error {
		_, err := strconv.ParseFloat(input, 64)
		if err != nil {
			return errors.New("Invalid input, please enter a float")
		}
		return nil
	}

	// Each template displays the formatted data received.
	templates := &promptui.PromptTemplates{
		Prompt:  "{{ . }} ",
		Valid:   "{{ . | blue }} ",
		Invalid: "{{ . | yellow }} ",
		Success: "{{ . | bold }} ",
	}

	prompt := promptui.Prompt{
		Label:     "Enter a float: ",
		Templates: templates,
		Validate:  validate,
	}

	result, err := prompt.Run()

	if err != nil {
		fmt.Printf("Prompt failed %v\n", err)
		return
	}

	// print out the result, if valid, error is displayed in a formatted message.
	fmt.Printf("Your float is: %s\n", result)
}

Output:

 

Create interactive CLI prompt with promptui

We'll use an promptui package to create an interactive select prompt:

package main

import (
	"fmt"

	"github.com/manifoldco/promptui"
)

func main() {
	prompt := promptui.Select{
		Label: "Select your characters:",
		Items: []string{"Harry Potter", "Ron Weasley", "Hermione Granger", "Ginny Weasley", "Neville Longbottom",
			"Luna Lovegood", "Draco Malfoy", "Albus Dumbledore"},
	}

	_, result, err := prompt.Run()

	if err != nil {
		fmt.Printf("Prompt failed %v\n", err)
		return
	}

	fmt.Printf("You choose %q\n", result)
}

Output:

 

Multi-Options prompt with survey package

To create an interactive multi-select prompt we're going to use an awesome survey package. Here is an simple example of multi-select prompt:

package main

import (
	"fmt"
	"strings"

	"github.com/AlecAivazis/survey/v2"
)

// list questions to ask
var qs = []*survey.Question{
	{
		Name:      "name",
		Prompt:    &survey.Input{Message: "Enter your name?"},
		Validate:  survey.Required,
		Transform: survey.Title,
	},
	{
		Name: "pet",
		Prompt: &survey.MultiSelect{
			Message: "Choose your pets:",
			Options: []string{"dogs", "reptiles", "cats", "birds", "fish", "rabbits", "pigs", "rats", "mices"},
			Default: "dogs",
		},
	},
	{
		Name:   "rating",
		Prompt: &survey.Input{Message: "Rate our website (integer number):"},
	},
}

func main() {
	// store answer to struct
	answer := struct {
		Name   string   // survey match the question and field names
		Pet    []string `survey:"pet"` //tag fields to match a specific name
		Rating int      // if the types don't match, survey will convert it
	}{}

	err := survey.Ask(qs, &answer)
	if err != nil {
		fmt.Println(err.Error())
		return
	}

	petString := strings.Join(answer.Pet, ", ")

	fmt.Printf("%s likes %s.", answer.Name, petString)
}

Output:

 

Summary

As you can see, basic interactive prompts are fairly simple to implement, but for more complex ones, some Go packages from the community are recommended: promptui, survey, prompter, term,... In today post, I have illustrate how to use promptui and survey to create some interesting examples with select, multi select options in prompt.

 

References

https://github.com/manifoldco/promptui
https://pkg.go.dev/golang.org/x/term

 

Tuan Nguyen

Tuan Nguyen

He is proficient in Golang, Python, Java, MongoDB, Selenium, Spring Boot, Kubernetes, Scrapy, API development, Docker, Data Scraping, PrimeFaces, Linux, Data Structures, and Data Mining. With expertise spanning these technologies, he develops robust solutions and implements efficient data processing and management strategies across various projects and platforms. You can connect with him on his LinkedIn profile.

Can't find what you're searching for? Let us assist you.

Enter your query below, and we'll provide instant results tailored to your needs.

If my articles on GoLinuxCloud has helped you, kindly consider buying me a coffee as a token of appreciation.

Buy GoLinuxCloud a Coffee

For any other feedbacks or questions you can send mail to admin@golinuxcloud.com

Thank You for your support!!

Leave a Comment