👨‍💻簡介

今天來介紹一個自己開發後端蠻常用的一個 package,promptui,拿來做menu真的很方便,promptui有兩個主要的輸入模式:

  1. Prompt:跳出單行使用者輸入。
  2. Select:提供一個選項列表供使用者選擇。

Prompt

prompt是一個struct,當執行Run時會返回輸入的結果

type Prompt struct {
    // Label is the value displayed on the command line prompt.
    //
    // The value for Label can be a simple string or a struct that will need to be accessed by dot notation
    // inside the templates. For example, `{{ .Name }}` will display the name property of a struct.
    Label interface{}

    // Default is the initial value for the prompt. This value will be displayed next to the prompt's label
    // and the user will be able to view or change it depending on the options.
    Default string

    // AllowEdit lets the user edit the default value. If false, any key press
    // other than <Enter> automatically clears the default value.
    AllowEdit bool

    // Validate is an optional function that fill be used against the entered value in the prompt to validate it.
    Validate ValidateFunc

    // Mask is an optional rune that sets which character to display instead of the entered characters. This
    // allows hiding private information like passwords.
    Mask rune

    // HideEntered sets whether to hide the text after the user has pressed enter.
    HideEntered bool

    // Templates can be used to customize the prompt output. If nil is passed, the
    // default templates are used. See the PromptTemplates docs for more info.
    Templates *PromptTemplates

    // IsConfirm makes the prompt ask for a yes or no ([Y/N]) question rather than request an input. When set,
    // most properties related to input will be ignored.
    IsConfirm bool

    // IsVimMode enables vi-like movements (hjkl) and editing.
    IsVimMode bool

    // the Pointer defines how to render the cursor.
    Pointer Pointer

    Stdin  io.ReadCloser
    Stdout io.WriteCloser
}

語法如下:

func (*promptui.Prompt).Run() (string, error)
package main

import (
	"fmt"
	"github.com/manifoldco/promptui"
)

func main() {

	prompt := promptui.Prompt{
		Label: "Anything",
	}
	result, err := prompt.Run()
	if err != nil {
		fmt.Printf("Prompt failed %v\n", err)
		return
	}
	fmt.Printf("You type %q\n", result)
}

確認(Confirm)

建立一個確認提示,使用者可以選擇是或否。

package main

import (
	"fmt"
	"github.com/manifoldco/promptui"
)

func main() {
	prompt := promptui.Prompt{
		Label:     "Delete all resources",
		IsConfirm: true,
	}

	_, err := prompt.Run()

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

	fmt.Printf("Resources deleted")
}

自定義提示(Custom Prompt)

這個功能是讓使用者可以自己定義提示的外觀和行為。例如,你可以更改提示的顏色,標籤和其他設定。

package main

import (
	"fmt"
	"errors"
	"github.com/manifoldco/promptui"
)

func main() {
	prompt := promptui.Prompt{
		Label: "Enter your name",
		Validate: func(input string) error {
			if len(input) < 3 {
				return errors.New("Name must have more than 3 characters")
			}
			return nil
		},
	}

	result, err := prompt.Run()

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

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

提示預設值(Prompt Default)

Promptui 支援設定提示的預設值。

package main

import (
	"fmt"
	"github.com/manifoldco/promptui"
)

func main() {
	prompt := promptui.Prompt{
		Label:    "Enter your name",
		Default:  "Alan",
	}

	result, err := prompt.Run()

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

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

密碼提示(Password Prompt)

Promptui 可以用來建立一個密碼提示,其中使用者輸入的文本將被掩蓋。

package main

import (
	"fmt"
	"github.com/manifoldco/promptui"
)

func main() {
	prompt := promptui.Prompt{
		Label: "Enter Password",
		Mask:  '*',
	}

	result, err := prompt.Run()

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

	fmt.Printf("Password entered: %q\n", result)
}

Select

Select也是一個struct,與Prompt不同的是當執行Run時會返回index以及選中的結果

type Select struct {
    // Label is the text displayed on top of the list to direct input. The IconInitial value "?" will be
    // appended automatically to the label so it does not need to be added.
    //
    // The value for Label can be a simple string or a struct that will need to be accessed by dot notation
    // inside the templates. For example, `{{ .Name }}` will display the name property of a struct.
    Label interface{}

    // Items are the items to display inside the list. It expect a slice of any kind of values, including strings.
    //
    // If using a slice of strings, promptui will use those strings directly into its base templates or the
    // provided templates. If using any other type in the slice, it will attempt to transform it into a string
    // before giving it to its templates. Custom templates will override this behavior if using the dot notation
    // inside the templates.
    //
    // For example, `{{ .Name }}` will display the name property of a struct.
    Items interface{}

    // Size is the number of items that should appear on the select before scrolling is necessary. Defaults to 5.
    Size int

    // CursorPos is the initial position of the cursor.
    CursorPos int

    // IsVimMode sets whether to use vim mode when using readline in the command prompt. Look at
    // https://godoc.org/github.com/chzyer/readline#Config for more information on readline.
    IsVimMode bool

    // HideHelp sets whether to hide help information.
    HideHelp bool

    // HideSelected sets whether to hide the text displayed after an item is successfully selected.
    HideSelected bool

    // Templates can be used to customize the select output. If nil is passed, the
    // default templates are used. See the SelectTemplates docs for more info.
    Templates *SelectTemplates

    // Keys is the set of keys used in select mode to control the command line interface. See the SelectKeys docs for
    // more info.
    Keys *SelectKeys

    // Searcher is a function that can be implemented to refine the base searching algorithm in selects.
    //
    // Search is a function that will receive the searched term and the item's index and should return a boolean
    // for whether or not the terms are alike. It is unimplemented by default and search will not work unless
    // it is implemented.
    Searcher list.Searcher

    // StartInSearchMode sets whether or not the select mode should start in search mode or selection mode.
    // For search mode to work, the Search property must be implemented.
    StartInSearchMode bool

    list *list.List

    // A function that determines how to render the cursor
    Pointer Pointer

    Stdin  io.ReadCloser
    Stdout io.WriteCloser
}

語法如下:

func (*promptui.Select).Run() (int, string, error)
func (*promptui.Select).RunCursorAt(cursorPos int, scroll int) (int, string, error)
func (*promptui.Select).ScrollPosition() int
package main

import (
	"fmt"
	"github.com/manifoldco/promptui"
)

func main() {
	prompt := promptui.Select{
		Label: "Select Day",
		Items: []string{"Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
			"Saturday", "Sunday"},
	}
	_, result, err := prompt.Run()
	if err != nil {
		fmt.Printf("Prompt failed %v\n", err)
		return
	}
	fmt.Printf("You choose %q\n", result)
}

自定義選擇(Custom Select)

除了基本的選擇提示外,Promptui 還允許使用者自定義選擇列表的外觀和行為。

package main

import (
	"fmt"
	"github.com/manifoldco/promptui"
)

func main() {
	prompt := promptui.Select{
		Label: "Choose Color",
		Items: []string{"Red", "Blue", "Green"},
		Templates: &promptui.SelectTemplates{
			Label:    "{{ . }}?",
			Active:   "\U0001F336 {{ . | red }}",
			Inactive: "  {{ . | cyan }}",
			Selected: "\U0001F336 {{ . | red | cyan }}",
		},
	}

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

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

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

選擇添加(Select Add)

Promptui 還允許使用者在選擇提示中添加新的選項。

package main

import (
	"fmt"
	"github.com/manifoldco/promptui"
)

func main() {
	items := []string{"Monday", "Tuesday", "Wednesday", "Thursday", "Friday"}
	prompt := promptui.SelectWithAdd{
		Label:    "What day is it?",
		Items:    items,
		AddLabel: "Other",
	}

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

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

	if idx == len(items) {
		fmt.Printf("You chose to add %q\n", result)
	} else {
		fmt.Printf("You chose %q\n", result)
	}
}

📚Reference