Rumah  >  Artikel  >  pembangunan bahagian belakang  >  Gesaan Bersarang dalam Go menggunakan promptui

Gesaan Bersarang dalam Go menggunakan promptui

王林
王林asal
2024-07-17 20:22:421147semak imbas

Saya sedang mengusahakan alat CLI yang ditulis dalam Go, menggunakan alat Cobra baru-baru ini, dan saya mempunyai kes penggunaan di mana saya memerlukan gesaan bersarang untuk salah satu arahan. Saya menggunakan promptui untuk gesaan dan saya tidak dapat mencari cara yang mudah untuk melakukan ini. Catatan pendek ini akan menunjukkan cara membuat gesaan bersarang menggunakan promptui. Kod yang lengkap boleh didapati di sini.

Kita perlu membuat projek Go kosong dahulu. Kami akan memanggilnya nested-prompt:

$ mkdir nested-prompt && cd nested-prompt
$ go mod init github.com/Thwani47/nested-prompt 

Kami kemudian akan memasang pakej cobra, cobra-cli dan promptui:

$ go get -u github.com/spf13/cobra@latest
$ go install github.com/spf13/cobra-cli@latest 
$ go get -u github.com/manifoldco/promptui

Kami boleh memulakan aplikasi CLI baharu menggunakan cobra-cli dan menambah arahan pada CLI kami

$ cobra-cli init            # initializes a new CLI application
$ cobra-cli add config      # adds a new command to the CLI named 'config'

Kami boleh membersihkan fail cmd/config.go dan mengalih keluar semua komen. Sepatutnya begini:

// 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)
}

Kami perlu membuat jenis tersuai terlebih dahulu untuk gesaan kami. Kami melakukannya dengan mentakrifkan struct promptItem seperti berikut

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
}

Enum PromptType membolehkan kami mengumpul pelbagai jenis input daripada gesaan kami, kami boleh menggesa pengguna untuk teks, atau nilai sensitif seperti kata laluan atau Kunci API, atau menggesa pengguna untuk memilih daripada senarai nilai yang ditentukan

Kami kemudiannya mentakrifkan fungsi promptInput yang akan meminta input daripada pengguna. Fungsi mengembalikan nilai rentetan yang dimasukkan oleh pengguna atau ralat jika gesaan gagal.

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
}

Kami kemudiannya mentakrifkan fungsi promptSelect yang membolehkan pengguna memilih daripada senarai pilihan. Fungsi mengembalikan nilai rentetan yang dipilih oleh pengguna atau ralat jika gesaan gagal.

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
}

Untuk mensimulasikan gesaan bersarang, kami akan mencipta fungsi promptNested yang akan membolehkan kami menggesa pengguna untuk nilai dan gesaan akan kekal aktif sehingga pengguna memilih "Selesai". Fungsi ini mengembalikan nilai boolean yang menunjukkan bahawa gesaan itu berjaya.

Komen dalam fungsi menerangkan perkara yang menjadi tanggungjawab setiap blok kod utama

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)
}

Kini kami mempunyai semua kaedah yang kami perlukan dan kami perlu mengujinya. Di dalam fungsi Run perintah configCmd, kami akan membuat senarai promptItem dan memanggil fungsi promptNested untuk menggesa pengguna untuk input. Fungsi Run sepatutnya kelihatan seperti ini:

// 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)
}

Bina dan uji aplikasi seperti berikut

$ go build . 
$ ./nested-prompt config

Hasilnya adalah seperti berikut
Nested Prompts in Go using promptui

Atas ialah kandungan terperinci Gesaan Bersarang dalam Go menggunakan promptui. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn