Ratatui

TUITerminalUIWidgetsCross-platform

GitHub概要

ratatui/ratatui

A Rust crate for cooking up terminal user interfaces (TUIs) 👨‍🍳🐀 https://ratatui.rs

ホームページ:https://ratatui.rs
スター14,115
ウォッチ44
フォーク440
作成日:2023年2月12日
言語:Rust
ライセンス:MIT License

トピックス

cliratatuirustterminalterminal-user-interfacetuiwidgets

スター履歴

ratatui/ratatui Star History
データ取得日時: 2025/7/25 11:09

Ratatui

Ratatuiは、Rustでターミナルユーザーインターフェース(TUI)を構築するための最新かつ最も人気のあるライブラリです。tui-rsの精神的後継として、活発なコミュニティによって開発・保守されています。イミディエートモードレンダリングと豊富なウィジェットセットにより、美しく高性能なターミナルアプリケーションを作成できます。

特徴

イミディエートモードレンダリング

  • フレームベース: 各フレームでUIを完全に再描画
  • シンプルなAPI: 状態管理が直感的
  • 高パフォーマンス: 最適化されたバッファリング
  • 予測可能: 描画順序が明確

豊富なウィジェット

  • 基本ウィジェット: Block、Paragraph、List、Table
  • グラフ系: Chart、Sparkline、Gauge、BarChart
  • レイアウト: Flexbox風のレイアウトシステム
  • カスタムウィジェット: 独自ウィジェットの作成が容易

クロスプラットフォーム

  • バックエンド対応: crossterm、termion、termwiz
  • OS対応: Windows、macOS、Linux
  • 非同期対応: async/await対応
  • カラー対応: 16色、256色、RGB色

開発者体験

  • 型安全: Rustの型システムを活用
  • 優れたドキュメント: 包括的な例とガイド
  • 活発なコミュニティ: 迅速なサポートと開発
  • 豊富なサンプル: 実用的な例が多数

基本的な使用方法

インストール

[dependencies]
ratatui = "0.30"
crossterm = "0.27"

Hello World

use color_eyre::Result;
use crossterm::event::{self, Event};
use ratatui::{DefaultTerminal, Frame};

fn main() -> Result<()> {
    color_eyre::install()?;
    let terminal = ratatui::init();
    let result = run(terminal);
    ratatui::restore();
    result
}

fn run(mut terminal: DefaultTerminal) -> Result<()> {
    loop {
        terminal.draw(render)?;
        if matches!(event::read()?, Event::Key(_)) {
            break Ok(());
        }
    }
}

fn render(frame: &mut Frame) {
    frame.render_widget("hello world", frame.area());
}

レイアウトとウィジェット

use ratatui::{
    layout::{Constraint, Direction, Layout, Rect},
    style::{Color, Modifier, Style, Stylize},
    text::{Line, Span},
    widgets::{Block, Borders, List, ListItem, Paragraph},
    Frame,
};

fn ui(frame: &mut Frame) {
    // レイアウトを作成
    let chunks = Layout::default()
        .direction(Direction::Vertical)
        .constraints([
            Constraint::Length(3),
            Constraint::Min(0),
            Constraint::Length(3),
        ])
        .split(frame.area());

    // ヘッダー
    let header = Paragraph::new("My TUI Application")
        .block(Block::default().borders(Borders::ALL))
        .style(Style::default().fg(Color::Yellow).add_modifier(Modifier::BOLD));
    frame.render_widget(header, chunks[0]);

    // メインコンテンツ
    let items = vec![
        ListItem::new("Item 1"),
        ListItem::new("Item 2").style(Style::default().fg(Color::Yellow)),
        ListItem::new("Item 3"),
    ];
    let list = List::new(items)
        .block(Block::default().borders(Borders::ALL).title("List"))
        .highlight_style(Style::default().add_modifier(Modifier::BOLD))
        .highlight_symbol("> ");
    frame.render_widget(list, chunks[1]);

    // フッター
    let footer = Paragraph::new("Press 'q' to quit")
        .block(Block::default().borders(Borders::ALL))
        .style(Style::default().fg(Color::Gray));
    frame.render_widget(footer, chunks[2]);
}

ステートフルなウィジェット

use ratatui::{
    widgets::{StatefulWidget, TableState},
    Frame,
};

struct App {
    table_state: TableState,
    items: Vec<Vec<String>>,
}

impl App {
    fn new() -> Self {
        Self {
            table_state: TableState::default(),
            items: vec![
                vec!["Row 1".to_string(), "Data 1".to_string()],
                vec!["Row 2".to_string(), "Data 2".to_string()],
                vec!["Row 3".to_string(), "Data 3".to_string()],
            ],
        }
    }

    fn next(&mut self) {
        let i = match self.table_state.selected() {
            Some(i) => {
                if i >= self.items.len() - 1 {
                    0
                } else {
                    i + 1
                }
            }
            None => 0,
        };
        self.table_state.select(Some(i));
    }

    fn previous(&mut self) {
        let i = match self.table_state.selected() {
            Some(i) => {
                if i == 0 {
                    self.items.len() - 1
                } else {
                    i - 1
                }
            }
            None => 0,
        };
        self.table_state.select(Some(i));
    }
}

高度な機能

カスタムウィジェット

use ratatui::{
    buffer::Buffer,
    layout::Rect,
    style::{Color, Style},
    widgets::Widget,
};

struct MyWidget {
    text: String,
    style: Style,
}

impl Widget for MyWidget {
    fn render(self, area: Rect, buf: &mut Buffer) {
        buf.set_string(area.x, area.y, &self.text, self.style);
    }
}

// 使用例
let widget = MyWidget {
    text: "Custom Widget".to_string(),
    style: Style::default().fg(Color::Magenta),
};
frame.render_widget(widget, area);

グラフとチャート

use ratatui::{
    symbols,
    widgets::{Axis, Chart, Dataset, GraphType},
};

let datasets = vec![
    Dataset::default()
        .name("data1")
        .marker(symbols::Marker::Dot)
        .graph_type(GraphType::Line)
        .style(Style::default().fg(Color::Cyan))
        .data(&[(0.0, 5.0), (1.0, 6.0), (2.0, 7.0)]),
];

let chart = Chart::new(datasets)
    .block(Block::default().title("Chart").borders(Borders::ALL))
    .x_axis(
        Axis::default()
            .title("X Axis")
            .style(Style::default().fg(Color::Gray))
            .bounds([0.0, 10.0])
            .labels(["0", "5", "10"]),
    )
    .y_axis(
        Axis::default()
            .title("Y Axis")
            .style(Style::default().fg(Color::Gray))
            .bounds([0.0, 10.0])
            .labels(["0", "5", "10"]),
    );

frame.render_widget(chart, area);

エコシステム

関連パッケージ

  • ratatui-macros: 便利なマクロ集
  • tui-textarea: テキストエリアウィジェット
  • tui-input: 入力フィールドウィジェット
  • tui-tree-widget: ツリービューウィジェット
  • tui-scrollview: スクロール可能なビュー
  • tui-logger: ログ表示ウィジェット

テンプレート

  • ratatui-templates: 公式テンプレート集
  • cargo-generate: プロジェクト生成ツール

実例プロジェクト

  • gitui: Git TUIクライアント
  • bottom: システムモニター
  • bandwhich: ネットワークモニター
  • diskonaut: ディスク使用状況ビューア

利点

  • モダンな設計: 最新のRustのベストプラクティスに従う
  • 活発な開発: 継続的な改善と新機能追加
  • 豊富な機能: 多様なウィジェットとレイアウトオプション
  • 優れた性能: 効率的なレンダリングアルゴリズム
  • クロスプラットフォーム: 主要なOSとターミナルエミュレータに対応

制約事項

  • 学習曲線: Rustの知識が必要
  • イミディエートモード: 複雑な状態管理は開発者の責任
  • ターミナル制限: ターミナルの機能に依存
  • マウスサポート: バックエンドに依存

他のライブラリとの比較

項目RatatuiCursivetui-realm
レンダリングイミディエートリテインドコンポーネント
学習コスト低〜中中〜高
パフォーマンス
柔軟性非常に高
ウィジェット豊富豊富拡張可能

まとめ

Ratatuiは、Rustで本格的なTUIアプリケーションを構築するための最も人気のある選択肢です。活発なコミュニティ、豊富な機能、優れたパフォーマンスを提供し、シンプルなCLIツールから複雑なダッシュボードまで幅広いアプリケーションの開発に適しています。特に、柔軟性と制御を重視する開発者にとって理想的な選択です。