Ich habe kürzlich mit dem Cobra-Tool an einem in Go geschriebenen CLI-Tool gearbeitet und hatte einen Anwendungsfall, bei dem ich eine verschachtelte Eingabeaufforderung für einen der Befehle benötigte. Ich habe promptui für die Eingabeaufforderungen verwendet und konnte keine einfache Möglichkeit finden, dies zu tun. In diesem kurzen Beitrag wird gezeigt, wie Sie mit promptui eine verschachtelte Eingabeaufforderung erstellen. Den vollständigen Code finden Sie hier.
Wir müssen zunächst ein leeres Go-Projekt erstellen. Wir nennen es nested-prompt:
$ mkdir nested-prompt && cd nested-prompt $ go mod init github.com/Thwani47/nested-prompt
Wir installieren dann die Pakete cobra, cobra-cli und promptui:
$ go get -u github.com/spf13/cobra@latest $ go install github.com/spf13/cobra-cli@latest $ go get -u github.com/manifoldco/promptui
Wir können eine neue CLI-Anwendung mit cobra-cli initialisieren und unserer CLI einen Befehl hinzufügen
$ cobra-cli init # initializes a new CLI application $ cobra-cli add config # adds a new command to the CLI named 'config'
Wir können die Datei cmd/config.go bereinigen und alle Kommentare entfernen. Es sollte so aussehen:
// cmd/config.go package cmd import ( "fmt" "github.com/spf13/cobra" ) var configCmd = &cobra.Command{ Use: "config", Short: "Configure settings for the application", Long: `Configure settings for the application`, Run: func(cmd *cobra.Command, args []string) { fmt.Println("config called") }, } func init() { rootCmd.AddCommand(configCmd) }
Wir müssen zunächst einen benutzerdefinierten Typ für unsere Eingabeaufforderung erstellen. Wir tun dies, indem wir eine promptItem-Struktur wie folgt definieren
type PromptType int const ( TextPrompt PromptType = 0 PasswordPrompt PromptType = 1 SelectPrompt PromptType = 2 ) type promptItem struct { ID string Label string Value string SelectOptions []string promptType PromptType }
Mit der PromptType-Enumeration können wir verschiedene Arten von Eingaben aus unseren Eingabeaufforderungen erfassen. Wir können den Benutzer zur Eingabe von Text oder sensiblen Werten wie Passwörtern oder API-Schlüsseln auffordern oder den Benutzer auffordern, aus einer Liste definierter Werte auszuwählen
Wir definieren dann eine promptInput-Funktion, die den Benutzer zur Eingabe auffordert. Die Funktion gibt den vom Benutzer eingegebenen Zeichenfolgenwert oder einen Fehler zurück, wenn die Eingabeaufforderung fehlschlägt.
func promptInput(item promptItem) (string, error) { prompt := promptui.Prompt{ Label: item.Label, HideEntered: true, } if item.promptType == PasswordPrompt { prompt.Mask = '*' } res, err := prompt.Run() if err != nil { fmt.Printf("Prompt failed %v\n", err) return "", err } return res, nil }
Wir definieren dann eine promptSelect-Funktion, die es dem Benutzer ermöglicht, aus einer Liste von Optionen auszuwählen. Die Funktion gibt den vom Benutzer ausgewählten Zeichenfolgenwert oder einen Fehler zurück, wenn die Eingabeaufforderung fehlschlägt.
func promptSelect(item selectItem) (string, error) { prompt := promptui.Select{ Label: item.Label, Items: item.SelectValues, HideSelected: true, } _, result, err := prompt.Run() if err != nil { fmt.Printf("Prompt failed %v\n", err) return "", err } return result, nil }
Um eine verschachtelte Eingabeaufforderung zu simulieren, erstellen wir eine promptNested-Funktion, die es uns ermöglicht, den Benutzer zur Eingabe eines Werts aufzufordern. Die Eingabeaufforderung bleibt aktiv, bis der Benutzer „Fertig“ auswählt. Die Funktion gibt einen booleschen Wert zurück, der angibt, dass die Eingabeaufforderung erfolgreich war.
Die Kommentare in der Funktion erklären, wofür jeder große Codeblock verantwortlich ist
func promptNested(promptLabel string, startingIndex int, items []*promptItem) bool { // Add a "Done" option to the prompt if it does not exist doneID := "Done" if len(items) > 0 && items[0].ID != doneID { items = append([]*promptItem{{ID: doneID, Label: "Done"}}, items...) } templates := &promptui.SelectTemplates{ Label: "{{ . }}?", Active: "\U0001F336 {{ .Label | cyan }}", Inactive: "{{ .Label | cyan }}", Selected: "\U0001F336 {{ .Label | red | cyan }}", } prompt := promptui.Select{ Label: promptLabel, Items: items, Templates: templates, Size: 3, HideSelected: true, CursorPos: startingIndex, // Set the cursor to the last selected item } idx, _, err := prompt.Run() if err != nil { fmt.Printf("Error occurred when running prompt: %v\n", err) return false } selectedItem := items[idx] // if the user selects "Done", return true and exit from the function if selectedItem.ID == doneID { return true } var promptResponse string // if the prompt type is Text or Password, prompt the user for input if selectedItem.promptType == TextPrompt || selectedItem.promptType == PasswordPrompt { promptResponse, err = promptInput(*selectedItem) if err != nil { fmt.Printf("Error occurred when running prompt: %v\n", err) return false } items[idx].Value = promptResponse } // if the prompt type is Select, prompt the user to select from a list of options if selectedItem.promptType == SelectPrompt { promptResponse, err = promptSelect(*selectedItem) if err != nil { fmt.Printf("Error occurred when running prompt: %v\n", err) return false } items[idx].Value = promptResponse } if err != nil { fmt.Printf("Error occurred when running prompt: %v\n", err) return false } // recursively call the promptNested function to allow the user to select another option return promptNested(idx, items) }
Jetzt haben wir alle Methoden, die wir brauchen, und wir müssen sie testen. Innerhalb der Run-Funktion des Befehls configCmd erstellen wir eine Liste von promptItem und rufen die Funktion promptNested auf, um den Benutzer zur Eingabe aufzufordern. Die Run-Funktion sollte so aussehen:
// create a list of prompt items items := []*promptItem{ { ID: "APIKey", Label: "API Key", promptType: PasswordPrompt, }, { ID: "Theme", Label: "Theme", promptType: SelectPrompt, SelectOptions: []string{"Dark", "Light"}, }, { ID: "Language", Label: "Preferred Language", promptType: SelectPrompt, SelectOptions: []string{"English", "Spanish", "French", "German", "Chinese", "Japanese"}, }, } // set the starting index to 0 to start at the first item in the list promptNested("Configuration Items", 0, items) for _, v := range items { fmt.Printf("Saving configuration (%s) with value (%s)...\n", v.ID, v.Value) }
Erstellen und testen Sie die Anwendung wie folgt
$ go build . $ ./nested-prompt config
Das Ergebnis ist wie folgt
Das obige ist der detaillierte Inhalt vonVerschachtelte Eingabeaufforderungen in Go mit promptui. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!