tview

TUIWidgetsTerminalCross-platformGo

GitHub概要

rivo/tview

Terminal UI library with rich, interactive widgets — written in Golang

スター12,396
ウォッチ121
フォーク628
作成日:2017年12月15日
言語:Go
ライセンス:MIT License

トピックス

golangterminal-baseduser-interface

スター履歴

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

tview

tviewは、Go言語向けのリッチなTUIライブラリで、低レベルライブラリであるtcell上に構築されています。テーブル、フォーム、リスト、モーダルなどの豊富なウィジェットを提供し、k9sなどの人気ツールで採用されています。

特徴

豊富なウィジェットセット

  • 基本ウィジェット: Box、Button、Checkbox、DropDown
  • 入力ウィジェット: InputField、TextArea、Form
  • 表示ウィジェット: List、Table、TreeView、TextView
  • レイアウト: Flex、Grid、Pages、Modal
  • 特殊ウィジェット: ProgressBar、Application

使いやすいAPI

  • 直感的な設計: ウィジェットベースのシンプルなAPI
  • チェーンメソッド: 設定を連続して記述可能
  • イベントハンドリング: コールバックベースのシンプルなイベント処理
  • フォーカス管理: 自動的なフォーカス切り替え

クロスプラットフォーム

  • OSサポート: Windows、macOS、Linux
  • ターミナル互換: 多様なターミナルエミュレータで動作
  • Unicodeサポート: 完全なUnicode対応
  • マウスサポート: マウスイベントの処理

パフォーマンス

  • 効率的なレンダリング: tcellによる高速描画
  • 差分更新: 必要な部分のみ再描画
  • 軽量: 最小限のメモリ使用
  • スレッドセーフ: 並行処理に対応

基本的な使用方法

インストール

go get github.com/rivo/tview

Hello World

package main

import (
    "github.com/rivo/tview"
)

func main() {
    // アプリケーションの作成
    app := tview.NewApplication()
    
    // テキストボックスの作成
    box := tview.NewBox().
        SetBorder(true).
        SetTitle("Hello, tview!").
        SetTitleAlign(tview.AlignCenter)
    
    // アプリケーションの実行
    if err := app.SetRoot(box, true).Run(); err != nil {
        panic(err)
    }
}

フォームの作成

package main

import (
    "github.com/gdamore/tcell/v2"
    "github.com/rivo/tview"
)

func main() {
    app := tview.NewApplication()
    
    // フォームの作成
    form := tview.NewForm().
        AddInputField("Name", "", 20, nil, nil).
        AddPasswordField("Password", "", 20, '*', nil).
        AddCheckbox("Remember me", false, nil).
        AddDropDown("Role", []string{"Admin", "User", "Guest"}, 1, nil).
        AddButton("Save", func() {
            // 保存処理
            app.Stop()
        }).
        AddButton("Cancel", func() {
            app.Stop()
        })
    
    form.SetBorder(true).
        SetTitle("Login Form").
        SetTitleAlign(tview.AlignLeft)
    
    // ESCキーで終了
    app.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
        if event.Key() == tcell.KeyEscape {
            app.Stop()
        }
        return event
    })
    
    if err := app.SetRoot(form, true).EnableMouse(true).Run(); err != nil {
        panic(err)
    }
}

テーブルの使用

package main

import (
    "fmt"
    "github.com/gdamore/tcell/v2"
    "github.com/rivo/tview"
)

func main() {
    app := tview.NewApplication()
    
    // テーブルの作成
    table := tview.NewTable().
        SetBorders(true).
        SetSelectable(true, false)
    
    // ヘッダーの設定
    headers := []string{"ID", "Name", "Age", "City"}
    for i, header := range headers {
        table.SetCell(0, i,
            tview.NewTableCell(header).
                SetTextColor(tcell.ColorYellow).
                SetAlign(tview.AlignCenter).
                SetSelectable(false))
    }
    
    // データの設定
    data := [][]string{
        {"1", "Alice", "30", "New York"},
        {"2", "Bob", "25", "Los Angeles"},
        {"3", "Charlie", "35", "Chicago"},
        {"4", "Diana", "28", "Boston"},
    }
    
    for r, row := range data {
        for c, cell := range row {
            table.SetCell(r+1, c,
                tview.NewTableCell(cell).
                    SetAlign(tview.AlignLeft))
        }
    }
    
    // 選択イベント
    table.SetSelectedFunc(func(row, column int) {
        if row > 0 {
            name := table.GetCell(row, 1).Text
            app.Stop()
            fmt.Printf("Selected: %s\n", name)
        }
    })
    
    // レイアウト
    flex := tview.NewFlex().
        AddItem(table, 0, 1, true).
        SetDirection(tview.FlexRow)
    
    if err := app.SetRoot(flex, true).EnableMouse(true).Run(); err != nil {
        panic(err)
    }
}

レイアウトの構築

package main

import (
    "github.com/rivo/tview"
)

func main() {
    app := tview.NewApplication()
    
    // サイドバー
    sidebar := tview.NewList().
        AddItem("Home", "Go to home", 'h', nil).
        AddItem("Settings", "Configure app", 's', nil).
        AddItem("Quit", "Exit application", 'q', func() {
            app.Stop()
        })
    sidebar.SetBorder(true).SetTitle("Menu")
    
    // メインコンテンツ
    main := tview.NewTextView().
        SetText("Welcome to tview!\n\nThis is the main content area.").
        SetDynamicColors(true).
        SetRegions(true).
        SetWordWrap(true)
    main.SetBorder(true).SetTitle("Content")
    
    // フッター
    footer := tview.NewTextView().
        SetText("Press 'q' to quit | Tab to switch focus").
        SetTextAlign(tview.AlignCenter)
    footer.SetBorder(true)
    
    // Flexレイアウト
    flex := tview.NewFlex().
        AddItem(sidebar, 20, 0, true).
        AddItem(tview.NewFlex().SetDirection(tview.FlexRow).
            AddItem(main, 0, 1, false).
            AddItem(footer, 3, 0, false),
            0, 1, false)
    
    if err := app.SetRoot(flex, true).EnableMouse(true).Run(); err != nil {
        panic(err)
    }
}

高度な機能

モーダルダイアログ

func showModal(app *tview.Application, message string) {
    modal := tview.NewModal().
        SetText(message).
        AddButtons([]string{"OK", "Cancel"}).
        SetDoneFunc(func(buttonIndex int, buttonLabel string) {
            if buttonLabel == "OK" {
                // OKボタンの処理
            }
            app.SetRoot(mainView, true)
        })
    
    app.SetRoot(modal, false)
}

ツリービュー

func createTreeView() *tview.TreeView {
    root := tview.NewTreeNode("Root").
        SetColor(tcell.ColorRed)
    
    tree := tview.NewTreeView().
        SetRoot(root).
        SetCurrentNode(root)
    
    // 子ノードの追加
    addNode := func(target *tview.TreeNode, name string) *tview.TreeNode {
        node := tview.NewTreeNode(name).
            SetReference(name).
            SetSelectable(true)
        target.AddChild(node)
        return node
    }
    
    // ツリー構造の構築
    node1 := addNode(root, "First")
    addNode(node1, "Child 1")
    addNode(node1, "Child 2")
    
    node2 := addNode(root, "Second")
    addNode(node2, "Child A")
    addNode(node2, "Child B")
    
    // 選択イベント
    tree.SetSelectedFunc(func(node *tview.TreeNode) {
        reference := node.GetReference()
        if reference != nil {
            node.SetColor(tcell.ColorGreen)
        }
    })
    
    return tree
}

ページ切り替え

func createPages() *tview.Pages {
    pages := tview.NewPages()
    
    // ページ1
    page1 := tview.NewTextView().
        SetText("This is page 1").
        SetTextAlign(tview.AlignCenter)
    page1.SetBorder(true).SetTitle("Page 1")
    
    // ページ2
    page2 := tview.NewTextView().
        SetText("This is page 2").
        SetTextAlign(tview.AlignCenter)
    page2.SetBorder(true).SetTitle("Page 2")
    
    // ページを追加
    pages.AddPage("page1", page1, true, true)
    pages.AddPage("page2", page2, true, false)
    
    return pages
}

プログレスバー

func createProgressBar() *tview.Box {
    progressBar := tview.NewBox().
        SetBorder(true).
        SetTitle("Progress")
    
    // カスタム描画関数
    progressBar.SetDrawFunc(func(screen tcell.Screen, x, y, width, height int) (int, int, int, int) {
        // プログレスの計算
        progress := 0.7 // 70%
        filled := int(float64(width) * progress)
        
        // プログレスバーの描画
        for i := 0; i < width; i++ {
            if i < filled {
                screen.SetContent(x+i, y+height/2, '█', nil, tcell.StyleDefault.Foreground(tcell.ColorGreen))
            } else {
                screen.SetContent(x+i, y+height/2, '░', nil, tcell.StyleDefault.Foreground(tcell.ColorGray))
            }
        }
        
        return x, y, width, height
    })
    
    return progressBar
}

エコシステム

人気プロジェクトでの採用

  • k9s: Kubernetes CLI
  • lazydocker: Docker TUI
  • wtf: ダッシュボードアプリ
  • dry: Docker管理ツール

関連プロジェクト

  • tcell: 低レベルターミナルライブラリ
  • cview: tviewのフォーク(コンカレント性重視)

利点

  • 豊富なウィジェット: 実用的なウィジェットが揃っている
  • 簡単なAPI: 直感的で学習しやすい
  • 安定性: 多くのプロダクションアプリで実績
  • クロスプラットフォーム: 主要OSすべてで動作
  • パフォーマンス: 効率的な描画

制約事項

  • カスタマイズ性: ウィジェットの外観カスタマイズが限定的
  • アーキテクチャ: 特定の設計パターンに従う必要がある
  • 拡張性: カスタムウィジェットの作成が複雑

他のライブラリとの比較

項目tviewBubble Teatermui
ウィジェット非常に豊富コンポーネント系ダッシュボード系
学習コスト低〜中
柔軟性非常に高
コミュニティ大きい非常に大きい中程度
用途汎用汎用ダッシュボード

まとめ

tviewは、Go言語でリッチなTUIアプリケーションを素早く構築したい開発者に最適なライブラリです。豊富なウィジェットセット、簡単なAPI、クロスプラットフォーム対応により、エンタープライズアプリケーションからシンプルなツールまで幅広い用途に対応できます。特に、フォームやテーブルを中心としたデータ駆動のアプリケーション開発に優れています。