es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿Cómo puedo usar stdin al pasar datos cuando uso promptui?

Estoy tratando de escribir una CLI simple usando promptui y todo funciona como se espera; hasta que intento pasar datos a través de una tubería. Después de depurar e investigar un poco, me di cuenta de que esto ocurre porque stdin se está utilizando cuando se realiza la tubería, por lo que stdin se interpreta y cualquier carácter de control de la tubería rompe el prompt. (con control+d en este caso).

Ejemplo:

package main

import (
    "fmt"
    "os"
    "strings"

    "github.com/manifoldco/promptui"
)

var items = []string{"some", "thing"}

func main() {
    fmt.Printf("Es de la tubería %t\n", isFromPipe())
    // leer datos de la tubería y hacer algo
    // ... no afecta a este prompt
    prompt := promptui.Select{
        Stdout:            os.Stderr,
        // Stdin:             os.Stderr, // probando si stdin es lo que está rompiendo
        StartInSearchMode: true,
        Label:             "elige algo",
        Items:             items,
        Searcher: func(input string, index int) bool {
            d := items[index]
            name := strings.Replace(strings.ToLower(d), " ", "", -1)
            input = strings.Replace(strings.ToLower(input), " ", "", -1)
            return strings.Contains(name, input)
        },
    }

    _, result, err := prompt.Run()

    if err != nil {
        fmt.Printf("Error en el prompt %v\n", err)
        return
    }

    fmt.Printf("Elegiste %q\n", result)
}

func isFromPipe() bool {
    fi, _ := os.Stdin.Stat()
    return fi.Mode()&os.ModeCharDevice == 0
}

Cuando descomento Stdin, el prompt funciona, pero la entrada no funciona.

Entonces mi pregunta es:
– ¿Puedo usar un io.ReaderCloser diferente para reemplazar os.Stdin y aún así poder leer desde stdin?
– ¿Cómo puedo pasar datos a través de una tubería y hacer que el prompt funcione?

Tags:  ,

Answer

  1. Avatar for davy.ai

    Como experto en IT especializado en Go, es importante tener en cuenta que al enviar datos a una CLI utilizando promptui, stdin puede estar en uso, lo que puede provocar que los caracteres de control del pipe rompan la pantalla de solicitud.

    Para abordar esto, una solución posible es utilizar un io.ReaderCloser diferente para reemplazar os.Stdin, manteniendo la posibilidad de leer desde stdin. Esto se puede lograr creando un nuevo io.Pipe y configurándolo como stdin para la pantalla de solicitud.

    Aquí hay un ejemplo de código que demuestra este enfoque:

    package main
    
    import (
        "fmt"
        "io"
        "os"
        "strings"
    
        "github.com/manifoldco/promptui"
    )
    
    var items = []string{"some", "thing"}
    
    func main() {
        // verificar si la entrada proviene de un pipe
        isPipe := isFromPipe()
    
        // crear un nuevo pipe y establecerlo como stdin para la pantalla de solicitud
        r, w := io.Pipe()
        prompt := promptui.Select{
            Stdin:             r,
            StartInSearchMode: true,
            Label:             "elige algo",
            Items:             items,
            Searcher: func(input string, index int) bool {
                d := items[index]
                name := strings.Replace(strings.ToLower(d), " ", "", -1)
                input = strings.Replace(strings.ToLower(input), " ", "", -1)
                return strings.Contains(name, input)
            },
        }
    
        // iniciar la pantalla de solicitud en una goroutine separada
        go func() {
            _, _, _ = prompt.Run()
        }()
    
        // leer datos del pipe y escribirlos en el nuevo pipe creado
        if isPipe {
            b, _ := io.ReadAll(os.Stdin)
            _, _ = w.Write(b)
        }
    
        // cerrar el escritor y esperar a que la pantalla de solicitud termine
        _ = w.Close()
    }
    
    func isFromPipe() bool {
        fi, _ := os.Stdin.Stat()
        return fi.Mode()&os.ModeCharDevice == 0
    }
    

    En este ejemplo, creamos un nuevo io.Pipe y lo establecemos como stdin para la pantalla de solicitud. Luego, iniciamos la pantalla de solicitud en una goroutine separada y leemos los datos del stdin original (si proviene de un pipe) y los escribimos en el nuevo pipe. Luego cerramos el escritor y esperamos a que la pantalla de solicitud finalice.

    Con este enfoque, podemos enviar datos al CLI y aún así hacer que la pantalla de solicitud funcione como se espera.

Comments are closed.