Interfaccia utente del terminale: BubbleTea (Go) vs Ratatui (Rust)

Panoramica rapida dei framework TUI stile Elm (Go) vs immediate-mode (Rust)

Indice

Due forti opzioni disponibili oggi per costruire interfacce utente per il terminale sono BubbleTea (Go) e Ratatui (Rust). Una ti fornisce un framework opinato nello stile Elm; l’altra una libreria flessibile in modalità immediata.

Questo post sintetizza cos’è ciascuna, mostra un esempio minimo per entrambe e suggerisce quando scegliere una o l’altra. Sì, fornisce anche alcuni link utili.

Crush UI - implementato utilizzando il framework BubbleTea

Crush UI (screenshot sopra) è implementato utilizzando il framework BubbleTea.

Cosa è BubbleTea?

BubbleTea è un framework Go per TUI basato su The Elm Architecture. Descrivi il tuo’app con un modello (stato) e tre elementi: Init (comando iniziale), Update (gestisci i messaggi, restituisci il nuovo modello e un comando opzionale), e View (renderizza l’interfaccia utente come una stringa). Il framework esegue il ciclo degli eventi, converte i tasti premuti e l’I/O in messaggi e ridisegna quando il modello cambia. Quindi: cosa è BubbleTea? In breve, è il modo divertente e con stato per costruire applicazioni per terminale in Go, con una singola fonte di verità e aggiornamenti prevedibili.

BubbleTea è pronto per la produzione (v1.x), ha decine di migliaia di stelle su GitHub e migliaia di importatori noti, e funziona in linea, a schermo intero o misto. Di solito lo si combina con Bubbles per i componenti (input, viewport, spinner) e Lip Gloss per lo stile. Se stai costruendo un TUI in Go, un primo passo solido è seguire le comuni strutture di progetto Go in modo che il tuo cmd/ e i pacchetti rimangano chiari man mano che l’app cresce.

Un programma BubbleTea minimo ha questo aspetto: un modello, Init, Update (che gestisce i messaggi chiave), e View che restituisce una stringa. Il runtime si occupa del 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 := "What should we buy?\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 + "\nPress q to quit.\n"
}

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

App notevoli costruite con BubbleTea includono Crush (l’agente di codifica TUI di Charm), Glow, Huh e molti strumenti dall’ecosistema dei progetti Go più popolari su GitHub . Per applicazioni Go più complesse potresti aggiungere iniezione di dipendenze e test unitari solidi test unitari in Go; le stesse idee si applicano ai modelli e ai comandi di BubbleTea.

Cosa è Ratatui?

Ratatui è una libreria Rust per TUI che utilizza modalità immediata di rendering: ogni frame descrivi l’intera UI (widget e layout), e Ratatui la disegna. Cosa è Ratatui? È uno strumento leggero e non opinato — non impone un modello nello stile Elm o una struttura specifica dell’app. Mantieni il tuo stato, esegui il tuo ciclo degli eventi (di solito con crossterm, termion o termwiz), e chiama terminal.draw(|f| { ... }) per il rendering. Quindi la differenza tra lo stile Elm e la modalità immediata è esattamente questa: nello stile Elm il framework gestisce il ciclo e tu reagisci tramite Update/View; nella modalità immediata tu gestisci il ciclo e ridisegni l’intera UI dallo stato corrente ogni frame.

Ratatui è utilizzato da 2.100+ crate e fidato da aziende come Netflix (es. bpftop), OpenAI, AWS (es. amazon-q-developer-cli) e Vercel. La versione 0.30.x è attuale, con forti documentazioni e backend opzionali. È una buona scelta quando si desidera il controllo completo su input e rendering, o quando si è già nell’ecosistema Rust.

Un’app Ratatui minima: inizializza il terminale, esegui un ciclo che disegna e poi legge gli eventi, e ripristina il terminale all’uscita.

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("Hello, Ratatui! Premi q per uscire.").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(())
}

Quindi: quando dovrei scegliere BubbleTea vs Ratatui? Scegli BubbleTea quando desideri la via più rapida per creare una TUI raffinata in Go, con un unico modello e un chiaro Update/View, e quando il tuo team o ecosistema è Go (es. stai già utilizzando ORM per Go o Ollama in Go). Scegli Ratatui quando hai bisogno di controllo massimo, sei in Rust, o stai costruendo TUI sensibili alle prestazioni o a risorse limitate; il suo design in modalità immediata e i backend opzionali offrono questa flessibilità.

Aspetto BubbleTea (Go) Ratatui (Rust)
Stile Architettura Elm (modello, Init/Update/View) Modalità immediata (tu gestisci il ciclo, disegna ogni frame)
Ecosistema Bubbles, Lip Gloss, 10k+ app, Crush 2.100+ crate, Netflix/OpenAI/AWS/Vercel
Migliore per Iterazione rapida, team Go, CLI Controllo, prestazioni, codice base Rust

Entrambi sono eccellenti scelte; la lingua preferita e quanto struttura vogliamo dal framework dovrebbero guidare la decisione.

Risorse esterne