La forma divertida, funcional y con estado de crear aplicaciones de terminal. Un marco de Go basado en The Elm Architecture. Bubble Tea es ideal para aplicaciones de terminal simples y complejas, ya sea en línea, de ventana completa o una combinación de ambas.
Bubble Tea se utiliza en producción e incluye una serie de características y optimizaciones de rendimiento que hemos agregado a lo largo del camino. Entre ellos se encuentra un renderizador estándar basado en velocidad de fotogramas, un renderizador para regiones desplazables de alto rendimiento que funciona junto con el renderizador principal y soporte para mouse.
Para comenzar, consulte el tutorial a continuación, los ejemplos, los documentos, los tutoriales en vídeo y algunos recursos comunes.
Asegúrese de consultar Bubbles, una biblioteca de componentes de interfaz de usuario comunes para Bubble Tea.
Bubble Tea se basa en los paradigmas de diseño funcional de The Elm Architecture, que funciona muy bien con Go. Es una forma encantadora de crear aplicaciones.
Este tutorial asume que tienes conocimientos prácticos de Go.
Por cierto, el código fuente no anotado de este programa está disponible en GitHub.
Para este tutorial, estamos haciendo una lista de compras.
Para comenzar, definiremos nuestro paquete e importaremos algunas bibliotecas. Nuestra única importación externa será la biblioteca Bubble Tea, a la que llamaremos tea
para abreviar.
package main
import (
"fmt"
"os"
tea "github.com/charmbracelet/bubbletea"
)
Los programas Bubble Tea se componen de un modelo que describe el estado de la aplicación y tres métodos simples en ese modelo:
Entonces, comencemos definiendo nuestro modelo que almacenará el estado de nuestra aplicación. Puede ser de cualquier tipo, pero una struct
suele tener más sentido.
type model struct {
choices [] string // items on the to-do list
cursor int // which to-do list item our cursor is pointing at
selected map [ int ] struct {} // which to-do items are selected
}
A continuación, definiremos el estado inicial de nuestra aplicación. En este caso, estamos definiendo una función para devolver nuestro modelo inicial; sin embargo, también podríamos definir fácilmente el modelo inicial como una variable en otro lugar.
func initialModel () model {
return model {
// Our to-do list is a grocery list
choices : [] string { "Buy carrots" , "Buy celery" , "Buy kohlrabi" },
// A map which indicates which choices are selected. We're using
// the map like a mathematical set. The keys refer to the indexes
// of the `choices` slice, above.
selected : make ( map [ int ] struct {}),
}
}
A continuación, definimos el método Init
. Init
puede devolver un Cmd
que podría realizar alguna E/S inicial. Por ahora, no necesitamos realizar ninguna E/S, por lo que para el comando, simplemente devolveremos nil
, que se traduce como "sin comando".
func ( m model ) Init () tea. Cmd {
// Just return `nil`, which means "no I/O right now, please."
return nil
}
El siguiente es el método de actualización. La función de actualización se llama cuando "suceden cosas". Su trabajo es observar lo que ha sucedido y devolver un modelo actualizado en respuesta. También puede devolver un Cmd
para que sucedan más cosas, pero por ahora no te preocupes por esa parte.
En nuestro caso, cuando un usuario presiona la flecha hacia abajo, el trabajo de Update
es notar que se presionó la flecha hacia abajo y mover el cursor en consecuencia (o no).
El mensaje "algo pasó" viene en forma de Msg
, que puede ser de cualquier tipo. Los mensajes son el resultado de alguna E/S que tuvo lugar, como la pulsación de una tecla, el tic del temporizador o una respuesta de un servidor.
Generalmente averiguamos qué tipo de Msg
recibimos con un cambio de tipo, pero también puedes usar una aserción de tipo.
Por ahora, solo nos ocuparemos de los mensajes tea.KeyMsg
, que se envían automáticamente a la función de actualización cuando se presionan las teclas.
func ( m model ) Update ( msg tea. Msg ) (tea. Model , tea. Cmd ) {
switch msg := msg .( type ) {
// Is it a key press?
case tea. KeyMsg :
// Cool, what was the actual key pressed?
switch msg . String () {
// These keys should exit the program.
case "ctrl+c" , "q" :
return m , tea . Quit
// The "up" and "k" keys move the cursor up
case "up" , "k" :
if m . cursor > 0 {
m . cursor --
}
// The "down" and "j" keys move the cursor down
case "down" , "j" :
if m . cursor < len ( m . choices ) - 1 {
m . cursor ++
}
// The "enter" key and the spacebar (a literal space) toggle
// the selected state for the item that the cursor is pointing at.
case "enter" , " " :
_ , ok := m . selected [ m . cursor ]
if ok {
delete ( m . selected , m . cursor )
} else {
m . selected [ m . cursor ] = struct {}{}
}
}
}
// Return the updated model to the Bubble Tea runtime for processing.
// Note that we're not returning a command.
return m , nil
}
Es posible que hayas notado que Ctrl+c y q arriba devuelven un comando tea.Quit
con el modelo. Se trata de un comando especial que indica al tiempo de ejecución de Bubble Tea que se cierre y salga del programa.
Por fin, es hora de renderizar nuestra interfaz de usuario. De todos los métodos, la vista es el más sencillo. Observamos el modelo en su estado actual y lo usamos para devolver una string
. ¡Esa cadena es nuestra interfaz de usuario!
Debido a que la vista describe toda la interfaz de usuario de su aplicación, no tiene que preocuparse por volver a dibujar la lógica y cosas así. Bubble Tea se encarga de ello por ti.
func ( m model ) View () string {
// The header
s := "What should we buy at the market? n n "
// Iterate over our choices
for i , choice := range m . choices {
// Is the cursor pointing at this choice?
cursor := " " // no cursor
if m . cursor == i {
cursor = ">" // cursor!
}
// Is this choice selected?
checked := " " // not selected
if _ , ok := m . selected [ i ]; ok {
checked = "x" // selected!
}
// Render the row
s += fmt . Sprintf ( "%s [%s] %s n " , cursor , checked , choice )
}
// The footer
s += " n Press q to quit. n "
// Send the UI for rendering
return s
}
El último paso es simplemente ejecutar nuestro programa. Pasamos nuestro modelo inicial a tea.NewProgram
y lo dejamos arrancar:
func main () {
p := tea . NewProgram ( initialModel ())
if _ , err := p . Run (); err != nil {
fmt . Printf ( "Alas, there's been an error: %v" , err )
os . Exit ( 1 )
}
}
Este tutorial cubre los conceptos básicos de la creación de una interfaz de usuario de terminal interactiva, pero en el mundo real también necesitará realizar E/S. Para obtener más información, consulte el Tutorial de comandos. Es bastante simple.
También hay varios ejemplos de Bubble Tea disponibles y, por supuesto, están Go Docs.
Dado que las aplicaciones Bubble Tea asumen el control de stdin y stdout, deberás ejecutar profundizar en modo sin cabeza y luego conectarte a él:
# Start the debugger
$ dlv debug --headless --api-version=2 --listen=127.0.0.1:43000 .
API server listening at: 127.0.0.1:43000
# Connect to it from another terminal
$ dlv connect 127.0.0.1:43000
Si no proporciona explícitamente el indicador --listen
, el puerto utilizado variará según la ejecución, por lo que pasarlo hace que el depurador sea más fácil de usar desde un script o el IDE de su elección.
Además, pasamos --api-version=2
porque delve tiene por defecto la versión 1 por razones de compatibilidad con versiones anteriores. Sin embargo, Delve recomienda usar la versión 2 para todos los desarrollos nuevos y es posible que algunos clientes ya no funcionen con la versión 1. Para obtener más información, consulte la documentación de Delve.
¡Realmente no puedes iniciar sesión en stdout con Bubble Tea porque tu TUI está ocupada ocupándolo! Sin embargo, puede iniciar sesión en un archivo incluyendo algo como lo siguiente antes de iniciar su programa Bubble Tea:
if len ( os . Getenv ( "DEBUG" )) > 0 {
f , err := tea . LogToFile ( "debug.log" , "debug" )
if err != nil {
fmt . Println ( "fatal:" , err )
os . Exit ( 1 )
}
defer f . Close ()
}
Para ver lo que se registra en tiempo real, ejecute tail -f debug.log
mientras ejecuta su programa en otra ventana.
¡Hay más de 8.000 aplicaciones creadas con Bubble Tea! Aquí hay algunos de ellos.
Para ver más aplicaciones creadas con Bubble Tea, consulte Charm & Friends. ¿Hay algo interesante que hayas hecho con Bubble Tea y quieras compartir? ¡Los relaciones públicas son bienvenidos!
Ver contribuir.
Nos encantaría escuchar tu opinión sobre este proyecto. ¡No dudes en enviarnos una nota!
Bubble Tea se basa en los paradigmas de The Elm Architecture de Evan Czaplicki et alia y el excelente go-tea de TJ Holowaychuk. Está inspirado en los grandes Zeichenorientierte Benutzerschnittstellen de tiempos pasados.
MIT
Parte del encanto.
Charm热爱开源 • Charm ama el código abierto • نحنُ نحب المصادر المفتوحة