ターミナルUI:BubbleTea(Go)vs Ratatui(Rust)

「Elmスタイル(Go)と即時モード(Rust)のTUIフレームワークの概観」

目次

現在、ターミナルユーザーインターフェース(TUI)を構築するための強力な2つの選択肢は、BubbleTea (Go) および Ratatui (Rust) です。
1つは、Elmスタイルの枠組みを提供する意見を表明したアプローチであり、もう1つは柔軟な即時モードのライブラリです。

この投稿では、それぞれの概要を紹介し、それぞれの最小限の例を示し、どちらを選ぶべきかを提案します。また、役に立つリンクも提供します。

Crush UI - BubbleTeaフレームワークを使用して実装

Crush UI(上記のスクリーンショット)は、BubbleTeaフレームワークを使用して実装されています。

什么是 BubbleTea?

BubbleTea は、The Elm Architecture に基づいた Go の TUI フレームワークです。アプリケーションを model(状態)と3つの要素で記述します:Init(初期コマンド)、Update(メッセージを処理し、新しい model とオプションのコマンドを返す)、および View(UI を文字列としてレンダリング)。このフレームワークはイベントループを実行し、キーボード入力やI/Oをメッセージに変換し、modelが変化すると再描画します。つまり、BubbleTeaとは何ですか? 一言で言えば、Goでターミナルアプリを構築するための楽しい、状態を持つ方法であり、単一の真理の源と予測可能な更新が可能です。

BubbleTeaは、v1.xで生産性が高く、GitHubで何万ものスターを獲得し、数千の既知のインポート者を有しています。インライン、フルスクリーン、またはミックス形式で動作します。通常は、Bubbles でコンポーネント(入力、ビューポート、スピナー)と Lip Gloss でスタイルを組み合わせて使用します。GoのTUIを構築している場合、最初のステップとして、Goプロジェクト構造 に従って、cmd/ とパッケージがアプリが成長するにつれて明確に保たれるようにすることが推奨されます。

最小限の BubbleTea プログラムは、model、InitUpdate(キーメッセージを処理)、View が文字列を返すように構成されています。残りはランタイムが処理します。

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

BubbleTeaで構築された著名なアプリには、Crush(CharmのTUIベースのAIコーディングエージェント)、Glow、Huh、および 最も人気のあるGoプロジェクト エコシステムからの多くのツールが含まれます。より複雑なGoアプリでは、依存性注入 と堅牢な ユニットテスト を追加することもできます。これらの考え方は、BubbleTeaモデルとコマンドにも適用されます。

什么是 Ratatui?

Ratatui は、即時モードレンダリングを使用する Rust の TUI ライブラリです:各フレームでは、UI(ウィジェットとレイアウト)全体を記述し、Ratatui がそれを描画します。Ratatuiとは何ですか? 軽量で無意見なツールキットであり、Elmスタイルのモデルや特定のアプリ構造を課しません。独自の状態を保持し、独自のイベントループを実行し(通常は crosstermtermion、または termwiz を使用)、terminal.draw(|f| { ... }) を呼び出して描画します。したがって、Elmスタイルと即時モードの違い はまさにこれです:Elmスタイルでは、フレームワークがループを所有し、Update/View経由で反応します。即時モードでは、ループを所有し、各フレームで現在の状態からUI全体を再描画します。

Ratatuiは2,100以上のクレートで使用されており、Netflix(例:bpftop)、OpenAI、AWS(例:amazon-q-developer-cli)、Vercelなどの企業が信頼しています。現在のバージョンは0.30.xで、強力なドキュメントとオプションのバックエンドが提供されています。入力とレンダリングの完全な制御が必要な場合、またはすでに Rustエコシステム にいる場合に最適です。

最小限の Ratatui アプリ:ターミナルを初期化し、描画してイベントを読み取るループを実行し、終了時にターミナルを復元します。

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! Press q to quit.").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(())
}

したがって、BubbleTeaとRatatuiのどちらを選ぶべきですか? BubbleTea を選ぶべきなのは、GoでポリッシュされたTUIを構築するための最速の道を望む場合、単一のmodelと明確なUpdate/Viewがあり、チームやエコシステムがGo(例:すでに Go ORM または GoでのOllamaの使用 を使用している)場合です。Ratatui を選ぶべきなのは、最大限の制御が必要な場合、Rustにいる場合、またはパフォーマンス敏感またはリソース制約のあるTUIを構築する場合です。その即時モードの設計とオプションのバックエンドがその柔軟性を提供します。

まとめ

項目 BubbleTea (Go) Ratatui (Rust)
スタイル Elmアーキテクチャ(model, Init/Update/View) 即時モード(ループは自分自身が所有し、各フレームで描画)
エコシステム Bubbles, Lip Gloss, 10,000以上のアプリ、Crush 2,100以上のクレート、Netflix/OpenAI/AWS/Vercel
最も適している クイックな反復、Goチーム、CLI 制御、パフォーマンス、Rustコードベース

両方とも優れた選択肢です。推奨される言語とフレームワークからどれほどの構造を望むかが決定の要因となります。

有用なリンク

外部リソース