Heim  >  Artikel  >  Backend-Entwicklung  >  Verschachtelte Eingabeaufforderungen in Go mit promptui

Verschachtelte Eingabeaufforderungen in Go mit promptui

王林
王林Original
2024-07-17 20:22:421078Durchsuche

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
Nested Prompts in Go using promptui

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!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn