iT邦幫忙

2025 iThome 鐵人賽

0
Rust

大家一起跟Rust當好朋友吧!系列 第 31

Day 31: 發現 Ratatui - 讓你的終端應用變得超有趣!

  • 分享至 

  • xImage
  •  

嗨嗨!大家好!歡迎來到 Rust 三十天挑戰的番外篇第三十一天!

經過前面三十天的學習,我們一起打造了一個完整的部落格後端 API。今天我想跟大家分享一個超級酷的 Rust 函式庫 —— Ratatui!這個函式庫讓我們可以在終端裡創造出美麗、實用的使用者介面,完全顛覆你對「終端應用程式」的刻板印象。

🤩 第一印象:「哇,終端還能這樣玩?」

還記得小時候看到駭客電影裡那些酷炫的終端介面嗎?或者你有用過 htoplazygit 這些漂亮的終端工具?沒錯,這些都是 TUI(Terminal User Interface)應用程式的典型例子!

與傳統的命令列工具相比:

  • 傳統 CLIlsgrepcurl - 執行完就結束,輸出文字後離開
  • 現代 TUIhtoplazygitspotify-tui - 有完整介面,可以即時互動

Ratatui 就是讓我們用 Rust 輕鬆打造這種酷炫 TUI 應用的神器!

🛠️ 五分鐘體驗 Ratatui

讓我們從最簡單的 "Hello, Ratatui!" 開始:

use ratatui::{
    backend::CrosstermBackend,
    layout::Alignment,
    style::{Color, Style},
    widgets::{Block, Borders, Paragraph},
    Terminal,
};
use std::io;
use crossterm::{event, execute};
use crossterm::event::{Event, KeyCode};
use crossterm::terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 設置終端
    enable_raw_mode()?;
    let mut stdout = io::stdout();
    execute!(stdout, EnterAlternateScreen)?;
    let backend = CrosstermBackend::new(stdout);
    let mut terminal = Terminal::new(backend)?;

    loop {
        terminal.draw(|frame| {
            let area = frame.area();
            let block = Block::default()
                .title("我的第一個 TUI 程式")
                .borders(Borders::ALL)
                .style(Style::default().fg(Color::Cyan));
            let paragraph = Paragraph::new("按 'q' 退出!")
                .block(block)
                .alignment(Alignment::Center);
            frame.render_widget(paragraph, area);
        })?;

        if event::poll(std::time::Duration::from_millis(50))? {
            if let Event::Key(key) = event::read()? {
                if let KeyCode::Char('q') = key.code {
                    break;
                }
            }
        }
    }

    // 清理終端
    disable_raw_mode()?;
    execute!(terminal.backend_mut(), LeaveAlternateScreen)?;
    Ok(())
}

把這段程式碼存成 main.rs,然後在 Cargo.toml 加上:

[dependencies]
ratatui = "0.30.0-alpha.5"
crossterm = "0.29.0"

執行 cargo run,你就會看到一個漂亮的終端介面!🎉

🎨 炫技時間:我的 Kanban 看板

說到 TUI 應用,我最近用 Ratatui 做了一個終端版的 Kanban 看板,讓我來跟大家分享一下這個專案!

🌟 功能特色

這個 Kanban TUI 應用包含了:

  • 多欄位看板:To Do、In Progress、Done 三個欄位
  • 任務管理:新增、編輯、刪除任務
  • 優先級系統:Low、Medium、High、Critical 四個層級,還有顏色標示!
  • Vim 風格操作hjkl 或方向鍵導航,就像在用 Vim 一樣順手
  • 資料持久化:自動儲存到 SQLite 資料庫
  • 即時互動:60fps 的絲滑體驗

🎮 操作方式

一般模式

  • h/j/k/l 或方向鍵 - 在欄位和任務間導航
  • n - 建立新任務
  • Enter - 編輯選中的任務
  • d - 刪除任務
  • m - 進入移動模式,M - 移到前一欄
  • q - 退出程式

編輯模式

  • 輸入文字編輯當前欄位
  • Tab - 下一個欄位
  • - 上一個欄位
  • +/= - 提高優先級,- - 降低優先級
  • Enter - 確認,Esc - 取消

🏗️ 架構設計心得

開發這個專案讓我深深體會到 Ratatui 的魅力:

1. 狀態驅動的 UI 模式

// App 結構體管理所有應用狀態
pub struct App {
    pub board: Board,
    pub selected_column: usize,
    pub selected_task: usize,
    pub input_mode: InputMode,
    pub edit_state: Option<EditState>,
}

// UI 就是狀態的純函數
fn ui(f: &mut Frame, app: &App) {
    // 根據當前狀態渲染介面
}

這種設計讓邏輯非常清晰:狀態變更 → UI 自動更新。

2. 模組化的輸入處理

pub fn handle_input(app: &mut App, key: KeyEvent) -> io::Result<bool> {
    match app.input_mode {
        InputMode::Normal => handle_normal_mode(app, key),
        InputMode::Editing => handle_editing_mode(app, key),
        InputMode::AddingTask => handle_adding_mode(app, key),
        InputMode::MovingTask => handle_moving_mode(app, key),
    }
}

不同模式有完全不同的鍵盤綁定,這讓應用程式可以有很豐富的互動方式。

3. 資料持久化

使用 SQLite 做資料存儲,讓看板狀態可以跨會話保存:

pub fn save_board(board: &Board) -> io::Result<()> {
    let conn = init_database()?;
    // 儲存到資料庫的邏輯
}

pub fn load_board() -> io::Result<Board> {
    let conn = init_database()?;
    // 從資料庫載入的邏輯
}

🚀 Ratatui 的神奇之處

豐富的元件庫

Ratatui 提供了超多好用的 UI 元件:

// 各種酷炫元件一應俱全
Chart::default()           // 圖表!
Table::default()           // 表格!
Gauge::default()          // 進度條!
Tabs::default()           // 分頁!
List::default()           // 清單!
Sparkline::default()      // 迷你圖表!
Calendar::default()       // 行事曆!

響應式布局系統

use ratatui::layout::{Constraint, Direction, Layout};

let chunks = Layout::default()
    .direction(Direction::Horizontal)
    .constraints([
        Constraint::Percentage(33),
        Constraint::Percentage(33), 
        Constraint::Percentage(34)
    ])
    .split(area);

一行程式碼就能做出響應式布局,自動適應任何終端大小!

豐富的樣式系統

use ratatui::style::{Color, Modifier, Style};

// 優先級顏色對應
let style = match task.priority {
    Priority::Critical => Style::default().fg(Color::Red),
    Priority::High => Style::default().fg(Color::Yellow),
    Priority::Medium => Style::default().fg(Color::Blue),
    Priority::Low => Style::default().fg(Color::Green),
};

💡 TUI 應用的無限可能

開發完這個 Kanban 專案後,我發現 TUI 應用的潛力真是無窮無盡:

🛠️ 開發工具類

  • API 測試工具:比 Postman 更輕量的終端版 API 測試器
  • 日誌查看器:即時監控應用程式 log,支援篩選和搜尋
  • 資料庫瀏覽器:終端版的資料庫管理工具
  • Git 工具:像 lazygit 那樣的視覺化 Git 操作介面

📊 監控與分析

  • 系統監控器:CPU、記憶體、網路使用情況的即時顯示
  • 網站流量分析:將 Google Analytics 資料視覺化
  • 股票價格追蹤器:即時股價圖表與技術分析

🎮 娛樂應用

  • 音樂播放器:終端版 Spotify,支援播放清單管理
  • RSS 閱讀器:訂閱管理與文章閱讀
  • 終端遊戲:俄羅斯方塊、貪食蛇、甚至小型 RPG!

💼 生產力工具

  • 時間追蹤器:番茄鐘技法的實作
  • 筆記管理:終端版 Notion,支援 Markdown 編輯
  • 密碼管理器:安全的密碼存儲與生成工具
  • 個人財務追蹤:收支記錄與預算管理

🤝 社群與學習資源

Ratatui 有一個非常活躍和友善的社群:

📚 官方資源

🌟 優秀專案參考

  • spotify-tui:Spotify 的終端介面
  • gitui:Git 操作的 TUI 工具
  • bottom:系統監控工具
  • bandwhich:網路使用監控

🎊 開始你的 TUI 之旅

如果你也想嘗試 TUI 開發,我的建議是:

1. 從簡單開始

先做個 Hello World,感受一下 Ratatui 的基本概念:

  • Terminal 和 Backend 的設置
  • 基本的 widget 使用
  • 事件處理循環

2. 參考官方範例

Ratatui 的範例程式碼寫得非常好,從中可以學到很多最佳實務。

3. 選個有趣的專案

做一個你自己會用的工具!我選擇做 Kanban 是因為我真的需要一個簡單的任務管理工具。

4. 別害怕犯錯

TUI 開發有它的學習曲線,特別是狀態管理和事件處理。多實驗、多嘗試,很快就會上手。

📦 快速開始模板

想立刻試試看嗎?這裡有個最小可用的專案模板:

Cargo.toml

[package]
name = "ratatui-first"
version = "0.1.0"
edition = "2024"

[dependencies]
ratatui = "0.30.0-alpha.5"
crossterm = "0.29.0"

main.rs

// 就是前面展示的 Hello World 程式碼
// 複製貼上就能跑!

執行 cargo run,你的第一個 TUI 應用就誕生了!

🎯 總結

三十天的 Rust 學習之旅到這裡就要告一段落了,但這絕不是結束,而是一個全新的開始!

從第一天的 "Hello, World!" 到第三十天的完整部落格後端,我們一起走過了 Rust 的基礎語法、所有權系統、錯誤處理、非同步程式設計,最後還打造了一個實用的 Web API。

今天的 Ratatui 分享,我希望能為大家開啟另一扇門:Rust 不僅僅適合做後端服務,它在終端應用開發上也同樣出色。無論是提升工作效率的工具,還是有趣的個人專案,TUI 都是一個很棒的選擇。

記住,學習程式語言最好的方式就是用它來解決實際問題。不管是部落格後端、Kanban 看板,還是任何你能想像到的應用,都可以成為你練習和成長的機會。

希望這三十一天的內容對大家有幫助。如果你也做了什麼有趣的 Rust 專案,歡迎分享出來讓大家看看!

讓我們一起繼續在 Rust 的世界裡探索和創造吧!


P.S. 我的 Kanban TUI 專案完整程式碼可以在 GitHub 上找到,歡迎大家 fork、修改,或是提供改進建議!讓我們一起把這個小工具變得更棒~

本文是「我的 Rust IT 鐵人賽三十天挑戰:大家一起跟Rust當好朋友吧!」系列的理論上的最終篇章。感謝大家的陪伴,希望有朝一日可以再次相遇!


上一篇
Day 30: 總結、打包 (Docker)
系列文
大家一起跟Rust當好朋友吧!31
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言