Interfaz de usuario de terminal: BubbleTea (Go) vs Ratatui (Rust)

Vista rápida de marcos TUI en estilo Elm (Go) vs. modo inmediato (Rust)

Índice

Dos opciones fuertes para construir interfaces de usuario para terminal hoy en día son BubbleTea (Go) y Ratatui (Rust). Una le da un marco opinionado estilo Elm; la otra una biblioteca flexible en modo inmediato.

Este post resume qué es cada uno, muestra un ejemplo mínimo para ambos y sugiere cuándo elegir uno u otro. Y sí, también proporciona algunos enlaces útiles.

Crush UI - implementado usando el marco BubbleTea

Crush UI (captura de pantalla anterior) está implementado usando el marco BubbleTea.

¿Qué es BubbleTea?

BubbleTea es un marco para interfaces de usuario de terminal (TUI) en Go basado en The Elm Architecture. Describe tu aplicación con un modelo (estado) y tres partes: Init (comando inicial), Update (manejar mensajes, devolver un nuevo modelo y un comando opcional) y View (renderizar la UI como una cadena). El marco ejecuta el bucle de eventos, convierte pulsaciones de teclas e I/O en mensajes y vuelve a dibujar cuando el modelo cambia. Entonces: ¿qué es BubbleTea? En resumen, es la forma divertida y con estado de construir aplicaciones de terminal en Go, con una única fuente de verdad y actualizaciones predecibles.

BubbleTea está listo para producción (v1.x), tiene miles de estrellas en GitHub y miles de importadores conocidos, y funciona en línea, a pantalla completa o mezclado. Normalmente lo combinas con Bubbles para componentes (entradas, vistas, spinners) y Lip Gloss para el estilo. Si estás construyendo una TUI en Go, un primer paso sólido es seguir estructuras comunes de proyecto Go para que cmd/ y los paquetes permanezcan claros a medida que la aplicación crece.

Un programa BubbleTea mínimo tiene esta apariencia: un modelo, Init, Update (manejando mensajes de teclado) y View devolviendo una cadena. El entorno de ejecución hace el resto.

package main

import (
    "fmt"
    "os"
    tea "github.com/charmbracelet/bubbletea"
)

type model struct {
    choices  []string
    cursor   int
    selected map[int]struct{}
}

func (m model) Init() tea.Cmd { return nil }

func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
    switch msg := msg.(type) {
    case tea.KeyMsg:
        switch msg.String() {
        case "ctrl+c", "q":
            return m, tea.Quit
        case "up", "k":
            if m.cursor > 0 { m.cursor-- }
        case "down", "j":
            if m.cursor < len(m.choices)-1 { m.cursor++ }
        case "enter", " ":
            if _, ok := m.selected[m.cursor]; ok {
                delete(m.selected, m.cursor)
            } else {
                m.selected[m.cursor] = struct{}{}
            }
        }
    }
    return m, nil
}

func (m model) View() string {
    s := "¿Qué debemos comprar?\n\n"
    for i, choice := range m.choices {
        cursor := " "
        if m.cursor == i { cursor = ">" }
        checked := " "
        if _, ok := m.selected[i]; ok { checked = "x" }
        s += fmt.Sprintf("%s [%s] %s\n", cursor, checked, choice)
    }
    return s + "\nPresiona q para salir.\n"
}

func main() {
    if _, err := tea.NewProgram(model{
        choices:  []string{"Comprar zanahorias", "Comprar apio", "Comprar kohlrabi"},
        selected: make(map[int]struct{}),
    }).Run(); err != nil {
        fmt.Printf("error: %v", err)
        os.Exit(1)
    }
}

Aplicaciones notables construidas con BubbleTea incluyen Crush (el agente de codificación de AI de Charm), Glow, Huh y muchas herramientas del ecosistema de proyectos Go más populares en GitHub. Para aplicaciones Go más complejas podrías añadir inyección de dependencias y pruebas unitarias sólidas en Go; las mismas ideas se aplican a los modelos y comandos de BubbleTea.

¿Qué es Ratatui?

Ratatui es una biblioteca de Rust para TUIs que usa modo inmediato de renderizado: cada frame describes toda la UI (widgets y diseño), y Ratatui lo dibuja. ¿Qué es Ratatui? Es una herramienta liviana y sin opiniones: no impone un modelo estilo Elm ni una estructura específica de aplicación. Mantienes tu propio estado, ejecutas tu propio bucle de eventos (normalmente con crossterm, termion o termwiz), y llamas a terminal.draw(|f| { ... }) para renderizar. Entonces, la diferencia entre el estilo Elm y el modo inmediato es exactamente esta: en el estilo Elm el marco posee el bucle y reaccionas a través de Update/View; en el modo inmediato tú posees el bucle y redibujas toda la UI desde el estado actual cada frame.

Ratatui es usado por más de 2,100 crates y confiado por empresas como Netflix (por ejemplo, bpftop), OpenAI, AWS (por ejemplo, amazon-q-developer-cli) y Vercel. La versión 0.30.x es la actual, con documentación sólida y backends opcionales. Es una buena opción cuando quieres control total sobre la entrada y el renderizado, o cuando ya estás en el ecosistema de Rust.

Una aplicación Ratatui mínima: inicializas el terminal, ejecutas un bucle que dibuja y luego lee eventos, y restauras el terminal al salir.

use crossterm::event::{self, Event, KeyCode};
use ratatui::{prelude::*, widgets::Paragraph};
use std::time::Duration;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut terminal = ratatui::init();
    loop {
        terminal.draw(|frame| {
            let area = frame.area();
            frame.render_widget(
                Paragraph::new("¡Hola, Ratatui! Presiona q para salir.").alignment(Alignment::Center),
                area,
            );
        })?;
        if event::poll(Duration::from_millis(250))? {
            if let Event::Key(key) = event::read()? {
                if key.code == KeyCode::Char('q') {
                    break;
                }
            }
        }
    }
    ratatui::restore();
    Ok(())
}

Entonces: ¿cuándo debo elegir entre BubbleTea y Ratatui? Elige BubbleTea cuando quieras el camino más rápido hacia una TUI pulida en Go, con un solo modelo y un claro Update/View, y cuando tu equipo o ecosistema sea Go (por ejemplo, ya estás usando ORMs en Go o Ollama en Go). Elige Ratatui cuando necesites el máximo control, estés en Rust, o estés construyendo aplicaciones TUI sensibles al rendimiento o con recursos limitados; su diseño en modo inmediato y backends opcionales le da esa flexibilidad.

Resumen

Aspecto BubbleTea (Go) Ratatui (Rust)
Estilo Arquitectura Elm (modelo, Init/Update/View) Modo inmediato (tú posees el bucle, dibuja cada frame)
Ecosistema Bubbles, Lip Gloss, 10k+ apps, Crush 2,100+ crates, Netflix/OpenAI/AWS/Vercel
Mejor para Iteración rápida, equipos Go, CLIs Control, rendimiento, código bases en Rust

Ambos son excelentes opciones; el idioma preferido y cuánta estructura queremos del marco deben guiar la decisión.

Enlaces útiles

Recursos externos