Perpustakaan untuk membangun permintaan interaktif dan dapat diakses pada terminal yang mendukung urutan pelarian ANSI.
Hei semuanya! Saya akhirnya menerima fakta bahwa saya tidak dapat lagi mendedikasikan waktu yang cukup untuk menjaga perpustakaan ini tetap hidup. Proyek ini melampaui harapan saya yang paling liar dan merupakan pengalaman yang luar biasa. Jika orang lain ingin mengambil alih pemeliharaan, silakan hubungi
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 )
} Contoh dapat ditemukan di examples/ direktori. Jalankan mereka untuk melihat perilaku dasar:
go run examples/simple.go
go run examples/validation.go Ada dua cara utama untuk mengeksekusi petunjuk dan mulai mengumpulkan informasi dari pengguna Anda: Ask dan AskOne . Perbedaan utama adalah apakah Anda tertarik untuk mengumpulkan satu informasi atau jika Anda memiliki daftar pertanyaan untuk ditanyakan jawaban siapa yang harus dikumpulkan dalam satu struct. Untuk sebagian besar usecases dasar, Ask seharusnya sudah cukup. Namun, untuk survei dengan logika percabangan yang rumit, kami sarankan Anda memecah pertanyaan Anda menjadi beberapa panggilan ke kedua fungsi ini agar sesuai dengan kebutuhan Anda.
Sebagian besar prompt mengambil konfigurasi berbutir halus melalui bidang pada struct yang Anda instantiate. Dimungkinkan juga untuk mengubah perilaku default survei dengan meloloskan AskOpts untuk Ask atau AskOne . Contoh dalam dokumen ini akan melakukan keduanya secara bergantian:
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 ) Bidang dan nilai yang berasal dari prompt Select dapat menjadi salah satu dari dua hal yang berbeda. Jika Anda melewati int bidang akan memiliki nilai indeks yang dipilih. Jika Anda malah melewati string, nilai string yang dipilih akan ditulis ke bidang.
Pengguna juga dapat menekan esc untuk mengubah siklus kemampuan melalui opsi dengan kunci J dan K untuk dilakukan masing -masing.
Secara default, prompt pilih dibatasi untuk menampilkan 7 opsi sekaligus dan akan memberi daftar opsi paginat lebih lama dari itu. Ini dapat diubah dengan beberapa cara:
// 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 ))Teks deskripsi opsional dapat digunakan untuk menambahkan informasi tambahan ke setiap opsi yang tercantum dalam prompt pilih:
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 ) Bidang dan nilai yang berasal dari prompt MultiSelect dapat menjadi salah satu dari dua hal yang berbeda. Jika Anda melewati int lapangan akan memiliki sepotong indeks yang dipilih. Jika Anda malah melewati string, sepotong nilai string yang dipilih akan ditulis ke bidang.
Pengguna juga dapat menekan esc untuk mengubah siklus kemampuan melalui opsi dengan kunci J dan K untuk dilakukan masing -masing.
Secara default, prompt multiselect terbatas untuk menampilkan 7 opsi sekaligus dan akan memberi daftar opsi lebih lama dari itu. Ini dapat diubah dengan beberapa cara:
// 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 ))Meluncurkan editor pilihan pengguna (ditentukan oleh variabel lingkungan $ visual atau $ editor) pada file sementara. Setelah pengguna keluar dari editor mereka, isi file sementara dibaca sebagai hasilnya. Jika tidak ada yang ada, notepad (pada windows) atau VIM (Linux atau Mac) digunakan.
Anda juga dapat menentukan pola untuk nama file sementara. Ini dapat berguna untuk memastikan sintaksis sintaks cocok dengan usecase Anda.
prompt := & survey. Editor {
Message : "Shell code snippet" ,
FileName : "*.sh" ,
}
survey . AskOne ( prompt , & content )Secara default, pengguna dapat memfilter untuk opsi di Select dan Multiselects dengan mengetik saat prompt aktif. Ini akan memfilter semua opsi yang tidak berisi string yang diketik di mana pun atas nama mereka, mengabaikan kasing.
Fungsi filter khusus juga dapat disediakan untuk mengubah perilaku ini:
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 ))Secara default filter akan hilang jika pengguna memilih salah satu elemen yang difilter. Setelah pengguna memilih satu elemen, pengaturan filter hilang.
Namun pengguna dapat mencegah hal ini terjadi dan menjaga filter aktif untuk beberapa pilihan dalam EG 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 )) Memvalidasi respons individu untuk pertanyaan tertentu dapat dilakukan dengan mendefinisikan bidang Validate pada survey.Question yang akan divalidasi. Fungsi ini mengambil jenis interface{} dan mengembalikan kesalahan untuk ditampilkan kepada pengguna, mendorong mereka untuk respons lain. Seperti biasa, validator dapat diberikan langsung ke prompt atau dengan 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 hadir dengan beberapa validator agar sesuai dengan situasi umum. Saat ini validator ini meliputi:
| nama | tipe yang valid | keterangan | catatan |
|---|---|---|---|
| Diperlukan | setiap | Menolak nol nilai dari jenis respons | Nilai Boolean Langsung Melewati Karena Nilai Nol (Salah) adalah respons yang valid |
| Minlength (n) | rangkaian | Menegakkan bahwa respons setidaknya panjang yang diberikan | |
| Maxlength (n) | rangkaian | Menegakkan bahwa respons tidak lebih dari panjang yang diberikan | |
| MaxItems (n) | [] OptionAnswer | Menegakkan bahwa respons tidak ada lagi pilihan yang ditunjukkan | |
| Minitems (n) | [] OptionAnswer | Menegakkan bahwa respons tidak kurang pilihan yang ditunjukkan |
Semua petunjuk memiliki bidang Help yang dapat didefinisikan untuk memberikan informasi lebih lanjut kepada pengguna Anda:
& survey. Input {
Message : "What is your phone number:" ,
Help : "Phone number should include the area code" ,
} Secara default, pengguna dapat memilih semua opsi multi-seleksi menggunakan tombol panah kanan. Untuk mencegah pengguna dapat melakukan ini (dan menghapus <right> to all pesan dari prompt), gunakan opsi 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 ()) Juga secara default, pengguna dapat menggunakan tombol panah kiri untuk membatalkan pemilihan semua opsi. Untuk mencegah pengguna dari dapat melakukan ini (dan menghapus pesan <left> to none dari prompt), gunakan opsi 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 ()) Dalam beberapa situasi ? adalah respons yang sangat valid. Untuk menangani ini, Anda dapat mengubah rune yang dicari survei dengan 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 ( '^' )) Mengubah ikon dan warna/formatnya dapat dilakukan dengan melewati opsi WithIcons . Format mengikuti pola yang diuraikan di sini. Misalnya:
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"
}))Ikon dan teks dan format defaultnya dirangkum di bawah ini:
| nama | teks | format | keterangan |
|---|---|---|---|
| Kesalahan | X | merah | Sebelum kesalahan |
| Membantu | Saya | cyan | Sebelum Bantuan SMS |
| Pertanyaan | ? | Hijau+HB | Sebelum pesan prompt |
| SELECTFOCUS | > | hijau | Menandai fokus saat ini dalam prompt Select dan MultiSelect |
| Tidak ditandai | [] | Default+HB | Menandai opsi yang tidak dipilih dalam prompt MultiSelect |
| MarkedOption | [X] | cyan+b | Menandai pilihan yang dipilih dalam prompt MultiSelect |
Survei akan memberikan jawaban cepat untuk tipe kustom Anda jika mereka mengimplementasikan antarmuka ini:
type Settable interface {
WriteAnswer ( field string , value interface {}) error
}Berikut adalah contoh cara menggunakannya:
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
) Anda dapat menguji prompt interaktif program Anda menggunakan GO-Expect. Perpustakaan dapat digunakan untuk mengharapkan kecocokan di Stdout dan merespons Stdin. Karena os.Stdout dalam proses go test bukanlah TTY, jika Anda memanipulasi kursor atau menggunakan survey , Anda akan memerlukan cara untuk menafsirkan urutan pelarian terminal / ANSI untuk hal -hal seperti CursorLocation . vt10x.NewVT10XConsole akan membuat konsol go-expect yang juga multiplex stdio ke terminal virtual dalam memori.
Untuk beberapa contoh, Anda dapat melihat salah satu tes dalam repo ini.
survey ?Survei bertujuan untuk mendukung sebagian besar emulator terminal; Ini mengharapkan dukungan untuk urutan pelarian ANSI. Ini berarti bahwa membaca dari Piped Stdin atau menulis ke Piped Stdout tidak didukung , dan cenderung memecahkan aplikasi Anda dalam situasi ini. Lihat #337
Biasanya, ketika Anda mengetik Ctrl-C, terminal mengenali ini sebagai tombol berhenti dan memberikan sinyal SIGINT ke proses, yang mengakhiri. Namun, survei untuk sementara mengkonfigurasi terminal untuk mengirimkan kode kontrol sebagai byte input biasa. Ketika survei membaca byte ^C (ASCII x03, "Akhir teks"), itu mengganggu survei saat ini dan mengembalikan github.com/AlecAivazis/survey/v2/terminal.InterruptErr dari Ask or AskOne . Jika Anda ingin menghentikan proses, tangani kesalahan yang dikembalikan dalam kode Anda:
err := survey . AskOne ( prompt , & myVar )
if err != nil {
if err == terminal. InterruptErr {
log . Fatal ( "interrupted" )
}
...
}