Eine Bibliothek zum Aufbau interaktiver und zugänglicher Eingabeaufforderungen in Terminals, die ANSI -Escape -Sequenzen unterstützen.
Hey alle! Ich habe mich endlich damit abgefunden, dass ich nicht mehr genug Zeit widmen kann, um diese Bibliothek am Leben zu erhalten. Dieses Projekt hat meine wildesten Erwartungen übertroffen und war eine großartige Erfahrung. Wenn jemand anderes Wartung übernehmen möchte, wenden Sie sich bitte an
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 )
} Beispiele finden Sie in den examples/ Verzeichnissen. Führen Sie sie aus, um grundlegendes Verhalten zu sehen:
go run examples/simple.go
go run examples/validation.go Es gibt zwei primäre Möglichkeiten, um Eingabeaufforderungen auszuführen und Informationen von Ihren Benutzern zu sammeln: Ask und AskOne . Der Hauptunterschied besteht darin, ob Sie daran interessiert sind, eine einzelne Information zu sammeln oder eine Liste von Fragen zu stellen, an deren Antworten in einer einzigen Struktur gesammelt werden sollten. Für die meisten grundlegenden Usecasen sollte Ask , ob fragen sollte. Für Umfragen mit komplizierter Verzweigungslogik empfehlen wir jedoch, dass Sie Ihre Fragen in mehrere Anrufe bei diesen beiden Funktionen unterteilen, um Ihren Anforderungen zu entsprechen.
Die meisten Eingabeaufforderungen erfordern eine feinkörnige Konfiguration über Felder auf den von Ihnen instanziellen Strukturen. Es ist auch möglich, die Standardverhalten von Survey zu ändern, indem AskOpts entweder Ask oder AskOne bestanden. Beispiele in diesem Dokument erledigen beide austauschbar:
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 ) Felder und Werte, die aus einer Select Eingabeaufforderung stammen, können eines von zwei verschiedenen Dingen sein. Wenn Sie ein int übergeben, hat das Feld den Wert des ausgewählten Index. Wenn Sie stattdessen eine Zeichenfolge übergeben, wird der ausgewählte Zeichenfolgenwert an das Feld geschrieben.
Der Benutzer kann auch esc drücken, um den Fähigkeitszyklus durch die Optionen mit den J- und K -Tasten umzuschalten, um sie nach unten zu erledigen.
Standardmäßig ist die SELECT -Eingabeaufforderung auf die Anzeige von 7 Optionen gleichzeitig beschränkt und paginieren Listen von Optionen länger. Dies kann auf verschiedene Arten geändert werden:
// 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 ))Der optionale Beschreibungstext kann verwendet werden, um jeder Option zusätzliche Informationen hinzuzufügen, die in der Eingabeaufforderung ausgewählt werden:
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 ) Felder und Werte, die aus einer MultiSelect -Eingabeaufforderung stammen, können eines von zwei verschiedenen Dingen sein. Wenn Sie ein int übergeben, hat das Feld eine Scheibe der ausgewählten Indizes. Wenn Sie stattdessen eine Zeichenfolge übergeben, wird eine Scheibe der ausgewählten Stringwerte an das Feld geschrieben.
Der Benutzer kann auch esc drücken, um den Fähigkeitszyklus durch die Optionen mit den J- und K -Tasten umzuschalten, um sie nach unten zu erledigen.
Standardmäßig ist die Multiselect -Eingabeaufforderung darauf beschränkt, 7 Optionen gleichzeitig anzuzeigen, und paginieren Listen von Optionen länger. Dies kann auf verschiedene Arten geändert werden:
// 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 ))Startet den bevorzugten Editor des Benutzers (definiert von den Variablen $ visual oder $ editor) in einer temporären Datei. Sobald der Benutzer seinen Editor verlässt, wird der Inhalt der temporären Datei als Ergebnis gelesen. Wenn keiner vorhanden ist, wird Notepad (unter Windows) oder VIM (Linux oder Mac) verwendet.
Sie können auch ein Muster für den Namen der temporären Datei angeben. Dies kann nützlich sein, um sicherzustellen, dass die Syntax -Übereinstimmung mit Ihrem Usecase entspricht.
prompt := & survey. Editor {
Message : "Shell code snippet" ,
FileName : "*.sh" ,
}
survey . AskOne ( prompt , & content )Standardmäßig kann der Benutzer nach Optionen in ausgewählten und multiselekten filtern, indem die Eingabeaufforderung aktiv ist. Dadurch wird alle Optionen herausgefiltert, die die eingegebene Zeichenfolge nirgendwo in ihrem Namen enthalten und den Fall ignorieren.
Eine benutzerdefinierte Filterfunktion kann auch bereitgestellt werden, um dieses Verhalten zu ändern:
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 ))Standardmäßig verschwindet der Filter, wenn der Benutzer eines der gefilterten Elemente auswählt. Sobald der Benutzer ein Element auswählt, ist die Filtereinstellung verschwunden.
Der Benutzer kann jedoch verhindern und den Filter für mehrere Auswahlen in einem EG -Multiselect aktiv halten:
// 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 )) Die Validierung individueller Antworten für eine bestimmte Frage kann durch Definieren eines Validate in der survey.Question durchgeführt werden. Diese Funktion nimmt eine interface{} Typ und gibt dem Benutzer einen Fehler zurück, der sie für eine andere Antwort auffordert. Wie üblich können Validatoren direkt an die Eingabeaufforderung oder mit survey.WithValidator zur Verfügung gestellt werden.
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 wird mit einigen Validatoren vorverpackt, um gemeinsame Situationen anzupassen. Derzeit umfassen diese Validatoren:
| Name | Gültige Typen | Beschreibung | Notizen |
|---|---|---|---|
| Erforderlich | beliebig | Lehnt Nullwerte des Antworttyps ab | Boolesche Werte passieren gerade durch, da der Nullwert (Falsch) eine gültige Antwort ist |
| Minlenlänge (n) | Saite | Erzwingt, dass eine Antwort mindestens die angegebene Länge ist | |
| MaxLength (n) | Saite | Erzwingt, dass eine Antwort nicht länger als die angegebene Länge ist | |
| Maxitems (n) | [] Optionanswer | Erzwingt, dass eine Antwort keine Auswahl mehr der angegebenen hat | |
| Minitems (n) | [] Optionanswer | Erzwingt, dass eine Antwort nicht weniger ausgewiesen ist |
Alle Eingabeaufforderungen verfügen über ein Help , das definiert werden kann, um Ihren Benutzern weitere Informationen bereitzustellen:
& survey. Input {
Message : "What is your phone number:" ,
Help : "Phone number should include the area code" ,
} Standardmäßig können Benutzer alle Multi-Select-Optionen mit der richtigen Pfeiltaste auswählen. Verwenden Sie <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 ()) Standardmäßig können Benutzer die linke Pfeiltaste verwenden, um alle Optionen abzuwählen. Verwenden Sie die Option WithRemoveSelectNone , damit Benutzer dazu in der Lage sind, dies zu tun (und die Nachricht aus der <left> to none zu entfernen.
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 ()) In einigen Situationen ? ist eine vollkommen gültige Antwort. Um dies zu bewältigen, können Sie die Rune, für die die Umfrage sucht, mit WithHelpInput ändern:
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 ( '^' )) Das Ändern der Symbole und der Farbe/des Formats kann durch Übergeben der Option WithIcons durchgeführt werden. Das Format folgt den hier beschriebenen Mustern. Zum Beispiel:
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"
}))Die Symbole und deren Standardtext und ihr Format sind unten zusammengefasst:
| Name | Text | Format | Beschreibung |
|---|---|---|---|
| Fehler | X | Rot | Vor einem Fehler |
| Helfen | ich | Cyan | Vor Hilfe des Textes |
| Frage | ? | Grün+Hb | Vor der Nachricht einer Eingabeaufforderung |
| SelectFocus | > | Grün | Markiert den aktuellen Fokus in Select und MultiSelect Eingabeaufforderungen |
| Nicht markierte | [] | Standard+Hb | Markiert eine nicht ausgewählte Option in einer MultiSelect -Eingabeaufforderung |
| Markierte Option | [X] | Cyan+b | Markiert eine ausgewählte Auswahl in einer MultiSelect -Eingabeaufforderung |
Die Umfrage weist Ihre benutzerdefinierten Typen ein Umforderungsantworten zu, wenn sie diese Schnittstelle implementieren:
type Settable interface {
WriteAnswer ( field string , value interface {}) error
}Hier ist ein Beispiel, wie man sie verwendet:
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
) Sie können die interaktiven Eingabeaufforderungen Ihres Programms mit Go-Exect testen. Die Bibliothek kann verwendet werden, um ein Match gegen Stdout zu erwarten und auf Stdin zu antworten. Da os.Stdout in einem go test -Testprozess kein TTY ist, benötigen Sie, wenn Sie den Cursor manipulieren oder survey verwenden, eine Möglichkeit, Terminal / ANSI -Escape -Sequenzen für Dinge wie CursorLocation zu interpretieren. vt10x.NewVT10XConsole erstellt eine go-expect Konsole, die auch Stdio in ein memory virtuelles Terminal multiplext.
Für einige Beispiele können Sie einen der Tests in diesem Repo sehen.
survey unterstützt?Die Umfrage zielt darauf ab, die meisten terminalen Emulatoren zu unterstützen. Es erwartet Unterstützung für ANSI -Fluchtsequenzen. Dies bedeutet, dass das Lesen von Piped Stdin oder Schreiben in Piped Stdout nicht unterstützt wird und Ihre Anwendung in diesen Situationen wahrscheinlich brechen kann. Siehe #337
Normalerweise erkennt das Terminal, wenn Sie Strg-C eingeben, dies als Beendigungstaste und liefert ein SIGINT-Signal an den Prozess, der es endet. Die Umfrage konfiguriert jedoch vorübergehend das Terminal, um Kontrollcodes als gewöhnliche Eingabebytes zu liefern. Wenn die Umfrage ein ^c Byte (ASCII x03, "Ende des Textes") liest, unterbricht sie die aktuelle Umfrage und gibt einen github.com/AlecAivazis/survey/v2/terminal.InterruptErr von Ask oder AskOne zurück. Wenn Sie den Prozess stoppen möchten, behandeln Sie den zurückgegebenen Fehler in Ihrem Code:
err := survey . AskOne ( prompt , & myVar )
if err != nil {
if err == terminal. InterruptErr {
log . Fatal ( "interrupted" )
}
...
}