0%

Go Package: survey

Go 交互式命令行工具库,提供了包括文本输入、选择菜单、确认提示、多项选择等多种交互类型,帮助快速构建交互式命令行页面。

安装

1
go get -u github.com/AlecAivazis/survey/v2

Prompt

Input 单行输入

1
2
3
4
5
var username string
prompt := &survey.Input{
Message: "Input username:",
}
survey.AskOne(prompt, &username)

image-20241225015619560

可以通过设置 Suggest 来给用户提供建议,帮助补全输入,Suggest 为由当前输入值返回建议值列表的方法。如下面补全文件路径示例。

1
2
3
4
5
6
7
8
9
var path string
prompt := &survey.Input{
Message: "Input file path:",
Suggest: func(toComplete string) []string {
files, _ := filepath.Glob(toComplete + "*")
return files
},
}
survey.AskOne(prompt, &path)

Multiline 多行输入

Select 单选

1
2
3
4
5
6
var tool string
prompt := &survey.Select{
Message: "Choose a tool:",
Options: []string{"toolA", "toolB", "toolC"},
}
survey.AskOne(prompt, &tool)

可以通过设置 Description 给每个选项添加描述, Description 为由选项值/序号返回描述的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var tool string
description := map[string]string{
"toolA": "Description for toolA",
"toolB": "Description for toolB",
"toolC": "Description for toolC",
}
prompt := &survey.Select{
Message: "Choose a tool:",
Options: []string{"toolA", "toolB", "toolC"},
Description: func(value string, index int) string {
return description[value]
},
}
survey.AskOne(prompt, &tool)

MultiSelect 多选

1
2
3
4
5
6
days := []string{}
prompt := &survey.MultiSelect{
Message: "What days do you prefer:",
Options: []string{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"},
}
survey.AskOne(prompt, &days)

image-20241226000302861

Confirm 确认

1
2
3
4
5
answer := false
prompt := &survey.Confirm{
Message: "Are you sure to continue?",
}
survey.AskOne(prompt, &answer)

image-20241226004601642

Password 密码

1
2
3
4
5
password := ""
prompt := &survey.Password{
Message: "Please type your password",
}
survey.AskOne(prompt, &password)

image-20241226004825233

Option

Validator

设置输入验证,提供输入验证函数(输入:输入值,返回 error),如果用户输入验证不通过,则提示错误,并重新提问。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var input string
prompt := &survey.Input{
Message: "Input number:",
}
// 验证输入为数字,并在0到10范围内
vaildInputNumber := func(val interface{}) error {
num, err := strconv.Atoi(val.(string))
if err != nil {
return fmt.Errorf("not number")
}
if num < 0 || num > 10 {
return fmt.Errorf("not in 0~10")
}
return nil
}
survey.AskOne(prompt, &input, survey.WithValidator(vaildInputNumber))

image-20241226013939360

Survey 库也提供了一些可直接调用的验证函数

  • Required:要求非空
  • MinLength(n):最小长度
  • MaxLength(n):最大长度

Ask

Ask支持连续问多个问题,设置多个问题,每个问题可以包括四个部分:

  • Name:与回答结构体里的元素对应,用于指名结果解析到哪个元素
  • Prompt:具体的问题
  • Vaildate:回答的验证方法
  • Transform:自动更改格式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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?"},
Validate: func(val interface{}) error {
_, err := strconv.Atoi(val.(string))
if err != nil {
return fmt.Errorf("not number")
}
return nil
},
},
}

answers := struct {
Name string // survey will match the question and field names
FavoriteColor string `survey:"color"` // or you can tag fields to match a specific name
Age int // if the types don't match, survey will convert it
}{}

// perform the questions
err := survey.Ask(qs, &answers)
if err != nil {
fmt.Println(err.Error())
return
}

image-20241226020405076

参考