用于在支持ANSI逃生序列的终端上构建交互式和可访问提示的库。
嘿,大家!我终于想到了一个事实,即我再也无法花费足够的时间来保持这个图书馆的活力。这个项目超出了我最疯狂的期望,这是一个很棒的经历。如果其他人想接管维护,请伸出援手
package main
import (
"fmt"
"github.com/AlecAivazis/survey/v2"
)
// the questions to ask
var 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 `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
}
fmt . Printf ( "%s chose %s." , answers . Name , answers . FavoriteColor )
}示例可以在examples/目录中找到。运行它们以查看基本行为:
go run examples/simple.go
go run examples/validation.go执行提示并开始向用户收集信息的主要方法有两种: Ask和AskOne 。主要区别是您是否有兴趣收集一条信息,还是您有一个问题列表要询问应将答案收集到单个结构中。对于大多数基本的用途, Ask应该就足够了。但是,对于具有复杂分支逻辑的调查,我们建议您将问题分解为对这两个功能的多个调用,以满足您的需求。
大多数提示通过您实例化的结构上的字段进行细粒的配置。也可以通过通过AskOpts进行Ask或AskOne来更改调查的默认行为。本文档中的示例既可以互换:
prompt := & Select {
Message : "Choose a color:" ,
Options : [] string { "red" , "blue" , "green" },
// can pass a validator directly
Validate : survey . Required ,
}
// or define a default for the single call to `AskOne`
// the answer will get written to the color variable
survey . AskOne ( prompt , & color , survey . WithValidator ( survey . Required ))
// or define a default for every entry in a list of questions
// the answer will get copied into the matching field of the struct as shown above
survey . Ask ( questions , & answers , survey . WithValidator ( survey . Required )) name := ""
prompt := & survey. Input {
Message : "ping" ,
}
survey . AskOne ( prompt , & name ) file := ""
prompt := & survey. Input {
Message : "inform a file to save:" ,
Suggest : func ( toComplete string ) [] string {
files , _ := filepath . Glob ( toComplete + "*" )
return files
},
}
}
survey . AskOne ( prompt , & file ) text := ""
prompt := & survey. Multiline {
Message : "ping" ,
}
survey . AskOne ( prompt , & text ) password := ""
prompt := & survey. Password {
Message : "Please type your password" ,
}
survey . AskOne ( prompt , & password ) name := false
prompt := & survey. Confirm {
Message : "Do you like pie?" ,
}
survey . AskOne ( prompt , & name ) color := ""
prompt := & survey. Select {
Message : "Choose a color:" ,
Options : [] string { "red" , "blue" , "green" },
}
survey . AskOne ( prompt , & color )来自Select提示的字段和值可能是两种不同的事物之一。如果通过一个int则该字段将具有所选索引的值。如果您传递字符串,则选择的字符串值将写入字段。
用户还可以按esc使用J和K键分别向下进行操作,以切换能力周期。
默认情况下,选择提示只能一次显示7个选项,并且会将选项的列表分页率更长。这可以改变多种方式:
// as a field on a single select
prompt := & survey. MultiSelect { ... , PageSize : 10 }
// or as an option to Ask or AskOne
survey . AskOne ( prompt , & days , survey . WithPageSize ( 10 ))可选的说明文本可用于为选择提示中列出的每个选项添加额外信息:
color := ""
prompt := & survey. Select {
Message : "Choose a color:" ,
Options : [] string { "red" , "blue" , "green" },
Description : func ( value string , index int ) string {
if value == "red" {
return "My favorite color"
}
return ""
},
}
survey . AskOne ( prompt , & color )
// Assuming that the user chose "red - My favorite color":
fmt . Println ( color ) //=> "red"
days := [] string {}
prompt := & survey. MultiSelect {
Message : "What days do you prefer:" ,
Options : [] string { "Sunday" , "Monday" , "Tuesday" , "Wednesday" , "Thursday" , "Friday" , "Saturday" },
}
survey . AskOne ( prompt , & days )来自MultiSelect提示的字段和值可能是两种不同的事情之一。如果通过一个int则该字段将具有所选索引的切片。相反,如果您传递字符串,则选择的字符串值的切片将写入字段。
用户还可以按esc使用J和K键分别向下进行操作,以切换能力周期。
默认情况下,多电选择提示只能一次显示7个选项,并且会将选项的列表分页率更长。这可以改变多种方式:
// as a field on a single select
prompt := & survey. MultiSelect { ... , PageSize : 10 }
// or as an option to Ask or AskOne
survey . AskOne ( prompt , & days , survey . WithPageSize ( 10 ))在临时文件上启动用户的首选编辑器(由$ Visual或$ Editor环境变量定义)。用户退出其编辑器后,结果将读取临时文件的内容。如果两个都不存在,则使用记事本(在Windows上)或VIM(Linux或Mac)。
您还可以为临时文件的名称指定模式。这对于确保语法突出显示与您的用例匹配可能很有用。
prompt := & survey. Editor {
Message : "Shell code snippet" ,
FileName : "*.sh" ,
}
survey . AskOne ( prompt , & content )默认情况下,用户可以通过在提示处活动时键入SELECT和MultiSelect中的选项过滤。这将滤除所有不包含其名称中任何位置的键入字符串的选项,忽略案例。
还可以提供自定义过滤功能以改变此行为:
func myFilter ( filterValue string , optValue string , optIndex int ) bool {
// only include the option if it includes the filter and has length greater than 5
return strings . Contains ( optValue , filterValue ) && len ( optValue ) >= 5
}
// configure it for a specific prompt
& Select {
Message : "Choose a color:" ,
Options : [] string { "red" , "blue" , "green" },
Filter : myFilter ,
}
// or define a default for all of the questions
survey . AskOne ( prompt , & color , survey . WithFilter ( myFilter ))默认情况下,如果用户选择过滤后的元素之一,则过滤器将消失。用户选择一个元素后,过滤器设置已消失。
但是,用户可以防止这种情况发生,并使滤波器在多选中的多个选择中保持活跃:
// configure it for a specific prompt
& Select {
Message : "Choose a color:" ,
Options : [] string { "light-green" , "green" , "dark-green" , "red" },
KeepFilter : true ,
}
// or define a default for all of the questions
survey . AskOne ( prompt , & color , survey . WithKeepFilter ( true ))可以通过在survey.Question中定义Validate字段来验证对特定问题的响应。此功能采用interface{}类型并返回错误以显示给用户,并提示他们进行其他响应。像往常一样,可以直接向提示或survey.WithValidator提供验证器。
q := & survey. Question {
Prompt : & survey. Input { Message : "Hello world validation" },
Validate : func ( val interface {}) error {
// since we are validating an Input, the assertion will always succeed
if str , ok := val .( string ) ; ! ok || len ( str ) > 10 {
return errors . New ( "This response cannot be longer than 10 characters." )
}
return nil
},
}
color := ""
prompt := & survey. Input { Message : "Whats your name?" }
// you can pass multiple validators here and survey will make sure each one passes
survey . AskOne ( prompt , & color , survey . WithValidator ( survey . Required ))survey与一些验证器预先包装以适应常见情况。当前这些验证器包括:
| 姓名 | 有效类型 | 描述 | 笔记 |
|---|---|---|---|
| 必需的 | 任何 | 拒绝响应类型的零值 | 布尔值直接通过,因为零值(false)是有效的响应 |
| 最小长度(n) | 细绳 | 强制执行响应至少是给定的长度 | |
| 最大长度(n) | 细绳 | 强制执行响应不超过给定的长度 | |
| 最大值(n) | [] optionanswer | 强制执行响应不再选择指示的 | |
| Minitems(n) | [] optionanswer | 强制执行响应对所指示的选择不少 |
所有提示都有一个Help字段,可以定义为您的用户提供更多信息:
& survey. Input {
Message : "What is your phone number:" ,
Help : "Phone number should include the area code" ,
}默认情况下,用户可以使用正确的箭头键选择所有多选项。为了防止用户能够执行此操作(并从提示符中删除<right> to all消息),请使用WithRemoveSelectAll选项:
import (
"github.com/AlecAivazis/survey/v2"
)
number := ""
prompt := & survey. Input {
Message : "This question has the select all option removed" ,
}
survey . AskOne ( prompt , & number , survey . WithRemoveSelectAll ())同样,默认情况下,用户可以使用左箭头键来取消所有选项。为了防止用户能够执行此操作(并从提示符中删除<left> to none消息),请使用WithRemoveSelectNone选项:
import (
"github.com/AlecAivazis/survey/v2"
)
number := ""
prompt := & survey. Input {
Message : "This question has the select all option removed" ,
}
survey . AskOne ( prompt , & number , survey . WithRemoveSelectNone ())在某些情况下?是一个完全有效的响应。为了处理这一点,您可以使用WithHelpInput更改调查的符文:
import (
"github.com/AlecAivazis/survey/v2"
)
number := ""
prompt := & survey. Input {
Message : "If you have this need, please give me a reasonable message." ,
Help : "I couldn't come up with one." ,
}
survey . AskOne ( prompt , & number , survey . WithHelpInput ( '^' ))更改图标及其颜色/格式可以通过WithIcons选项来完成。格式遵循此处概述的模式。例如:
import (
"github.com/AlecAivazis/survey/v2"
)
number := ""
prompt := & survey. Input {
Message : "If you have this need, please give me a reasonable message." ,
Help : "I couldn't come up with one." ,
}
survey . AskOne ( prompt , & number , survey . WithIcons ( func ( icons * survey. IconSet ) {
// you can set any icons
icons . Question . Text = "⁇"
// for more information on formatting the icons, see here: https://github.com/mgutz/ansi#style-format
icons . Question . Format = "yellow+hb"
}))图标及其默认文本和格式如下:
| 姓名 | 文本 | 格式 | 描述 |
|---|---|---|---|
| 错误 | x | 红色的 | 错误之前 |
| 帮助 | 我 | 青色 | 在帮助文本之前 |
| 问题 | ? | 绿色+HB | 提示之前 |
| SelectFocus | > | 绿色的 | 标记当前的Select和MultiSelect提示中的重点 |
| 未标记 | [] | 默认+HB | 在MultiSelect提示中标记未选择的选项 |
| 标记 | [x] | 青色+b | 在MultiSelect提示中标记选择的选择 |
调查将对您的自定义类型的及时答案分配此接口:
type Settable interface {
WriteAnswer ( field string , value interface {}) error
}这是一个如何使用它们的示例:
type MyValue struct {
value string
}
func ( my * MyValue ) WriteAnswer ( name string , value interface {}) error {
my . value = value .( string )
}
myval := MyValue {}
survey . AskOne (
& survey. Input {
Message : "Enter something:" ,
},
& myval
)您可以使用Go-evect测试程序的交互提示。该库可用于期望在Stdout上进行匹配并在STDIN上做出响应。由于os.Stdout在go test过程中不是TTY,因此,如果您正在操纵光标或使用survey ,则需要一种解释CursorLocation之类的终端 / ANSI逃生序列的方法。 vt10x.NewVT10XConsole将创建一个go-expect Console,该控制台还将STDIO多重到内存虚拟终端。
对于一些示例,您可以在此存储库中看到任何测试。
survey支持哪些IO?调查旨在支持大多数终端模拟器;它预计支持ANSI逃生序列。这意味着不支持从管道的stdin或写作到管道的Stdout的阅读,并且在这些情况下可能会破坏您的应用程序。参见#337
通常,当您键入CTRL-C时,终端将其识别为退出按钮,并将Sigint信号传递到该过程,从而终止它。但是,调查会临时配置终端以将控制代码作为普通输入字节传递。当调查读取A ^c字节(ASCII X03,“文本的结尾”)时,它会中断当前的调查并返回github.com/AlecAivazis/survey/v2/terminal.InterruptErr from Ask或AskOne 。如果要停止该过程,请处理代码中返回的错误:
err := survey . AskOne ( prompt , & myVar )
if err != nil {
if err == terminal. InterruptErr {
log . Fatal ( "interrupted" )
}
...
}