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プロンプトを実行してユーザーから情報の収集を開始する2つの主要な方法があります: Ask and AskOne 。主な違いは、単一の情報を収集することに興味があるのか、それとも単一の構造体で誰の回答を収集する必要があるかを尋ねる質問のリストがあるかどうかです。ほとんどの基本的なユーザーの場合、 Askだけで十分です。ただし、複雑な分岐ロジックを備えた調査では、ニーズに合わせてこれらの機能の両方に複数のコールに質問を分割することをお勧めします。
ほとんどのプロンプトは、インスタンス化する構造体のフィールドを介してきめ細かい構成を取ります。また、 AskOpts AskまたはAskOneいずれかに渡すことにより、Surveyのデフォルトの動作を変更することもできます。このドキュメントの例は、両方の両方を互換性があります。
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プロンプトから生じるフィールドと値は、2つの異なるものの1つです。 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プロンプトに由来するフィールドと値は、2つの異なるものの1つです。 INT 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)が使用されます。
一時ファイルの名前のパターンを指定することもできます。これは、USECaseと一致する構文を強調表示するのに役立ちます。
prompt := & survey. Editor {
Message : "Shell code snippet" ,
FileName : "*.sh" ,
}
survey . AskOne ( prompt , & content )デフォルトでは、ユーザーは、プロンプトのアクティブ中に入力することにより、選択およびマルチセレクトのオプションをフィルタリングできます。これにより、ケースを無視して、名前のどこにも入力された文字列が含まれていないすべてのオプションが除外されます。
この動作を変更するために、カスタムフィルター関数を提供することもできます。
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 ))デフォルトでは、ユーザーがフィルタリングされた要素の1つを選択すると、フィルターが消えます。ユーザーが1つの要素を選択すると、フィルター設定がなくなります。
ただし、ユーザーはこれが発生しないようにし、MultiSelect:の複数の選択のフィルターをアクティブに保つことができます。
// 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)が有効な応答であるため、ブール値は直接通過します |
| minlength(n) | 弦 | 応答は少なくとも与えられた長さであることを強制します | |
| maxlength(n) | 弦 | 応答は与えられた長さよりももはやないことを強制します | |
| maxitems(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を削除する)、Option 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削除する)、Option 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プロンプトで選択されていないオプションをマークします |
| Markedoption | [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-Expectを使用して、プログラムのインタラクティブなプロンプトをテストできます。ライブラリを使用して、Stdoutでの試合を期待し、Stdinで応答できます。 go testプロセスのos.StdoutはTTYではないため、カーソルを操作したりsurveyを使用している場合、ターミナル / ANSIエスケープシーケンスをCursorLocationなどのものに解釈する方法が必要です。 vt10x.NewVT10XConsole 、メモリの仮想端子にSTDIOをマルチプレックスするgo-expect Consoleを作成します。
いくつかの例として、このリポジトリのいずれかのテストを見ることができます。
surveyでサポートされていますか?調査の目的は、ほとんどのターミナルエミュレーターをサポートすることを目的としています。 ANSIエスケープシーケンスのサポートが期待されています。これは、パイプされたstdinからの読み取りまたはパイプされたstdoutへの書き込みがサポートされておらず、これらの状況でアプリケーションを破る可能性が高いことを意味します。 #337を参照してください
通常、CTRL-Cを入力すると、端末はこれをQUITボタンとして認識し、プロセスにSIGINT信号を提供します。ただし、調査では、通常の入力バイトとして制御コードを配信するように端末を一時的に構成します。調査でa ^cバイト(ascii x03、 "end of text")を読み取ると、現在の調査を中断し、 github.com/AlecAivazis/survey/v2/terminal.InterruptErr /survey/v2/terminal.interrupterrをAskまたはAskOneから返します。プロセスを停止したい場合は、コードの返されたエラーを処理します。
err := survey . AskOne ( prompt , & myVar )
if err != nil {
if err == terminal. InterruptErr {
log . Fatal ( "interrupted" )
}
...
}