はじめに
Go言語でターミナルアプリを作る時に便利なパッケージBubble Tea
を使ってターミナルに
のようなテーブルを表示する方法の紹介です。
Bubble Teaのサンプル
テーブル表示のサンプルは、
にあります。
ソースコードの要点を抜粋すると
package main
import (
"fmt"
"os"
"github.com/charmbracelet/bubbles/table"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
)
// テーブルのスタイル
var baseStyle = lipgloss.NewStyle().
BorderStyle(lipgloss.NormalBorder()).
BorderForeground(lipgloss.Color("240"))
type model struct {
table table.Model
}
func (m model) Init() tea.Cmd { return nil }
// 更新メッセージの処理
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmd tea.Cmd
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {
case "esc":
if m.table.Focused() {
m.table.Blur()
} else {
m.table.Focus()
}
case "q", "ctrl+c":
return m, tea.Quit
case "enter":
return m, tea.Batch(
tea.Printf("Let's go to %s!", m.table.SelectedRow()[1]),
)
}
}
m.table, cmd = m.table.Update(msg)
return m, cmd
}
// 表示する
func (m model) View() string {
return baseStyle.Render(m.table.View()) + "\n"
}
func main() {
//カラム
columns := []table.Column{
{Title: "Rank", Width: 4},
{Title: "City", Width: 10},
{Title: "Country", Width: 10},
{Title: "Population", Width: 10},
}
// データ(省略しています)
rows := []table.Row{
{"1", "Tokyo", "Japan", "37,274,000"},
{"2", "Delhi", "India", "32,065,760"},
}
// テーブルの作成
t := table.New(
table.WithColumns(columns),
table.WithRows(rows),
table.WithFocused(true),
table.WithHeight(7),
)
// テーブルのスタイル設定(ヘッダー、選択時の表示など)
s := table.DefaultStyles()
s.Header = s.Header.
BorderStyle(lipgloss.NormalBorder()).
BorderForeground(lipgloss.Color("240")).
BorderBottom(true).
Bold(false)
s.Selected = s.Selected.
Foreground(lipgloss.Color("229")).
Background(lipgloss.Color("57")).
Bold(false)
t.SetStyles(s)
// プログラムを起動
m := model{t}
if _, err := tea.NewProgram(m).Run(); err != nil {
fmt.Println("Error running program:", err)
os.Exit(1)
}
}
です。このまま動作させると
のように画面の一部にしか表示されません。ターミナルをリサイズしても大きさは変わりません。
画面の大きさに合わせてリサイズできるようにする
少し変更するだけで、画面に合わせてリサイズできるようになります。
package main
import (
"fmt"
"os"
"github.com/charmbracelet/bubbles/table"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
)
var baseStyle = lipgloss.NewStyle().
BorderStyle(lipgloss.NormalBorder()).
BorderForeground(lipgloss.Color("240"))
+ var columns = []table.Column{
+ {Title: "Rank", Width: 4},
+ {Title: "City", Width: 10},
+ {Title: "Country", Width: 10},
+ {Title: "Population", Width: 10},
+}
type model struct {
table table.Model
}
func (m model) Init() tea.Cmd { return nil }
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmd tea.Cmd
switch msg := msg.(type) {
+ case tea.WindowSizeMsg:
+ m.table.SetWidth(msg.Width - 4)
+ m.table.SetHeight(msg.Height - 4)
+ w := m.table.Width() - 6
+ columns[0].Width = w * 4 / 34
+ columns[1].Width = w * 10 / 34
+ columns[2].Width = w * 10 / 34
+ columns[3].Width = w * 10 / 34
+ m.table.SetColumns(columns)
case tea.KeyMsg:
switch msg.String() {
case "esc":
if m.table.Focused() {
m.table.Blur()
} else {
m.table.Focus()
}
case "q", "ctrl+c":
return m, tea.Quit
case "enter":
return m, tea.Batch(
tea.Printf("Let's go to %s!", m.table.SelectedRow()[1]),
)
}
}
m.table, cmd = m.table.Update(msg)
return m, cmd
}
func (m model) View() string {
return baseStyle.Render(m.table.View()) + "\n"
}
func main() {
- columns := []table.Column{
- {Title: "Rank", Width: 4},
- {Title: "City", Width: 10},
- {Title: "Country", Width: 10},
- {Title: "Population", Width: 10},
- }
rows := []table.Row{
{"1", "Tokyo", "Japan", "37,274,000"},
{"2", "Delhi", "India", "32,065,760"},
}
t := table.New(
table.WithColumns(columns),
table.WithRows(rows),
table.WithFocused(true),
table.WithHeight(7),
)
s := table.DefaultStyles()
s.Header = s.Header.
BorderStyle(lipgloss.NormalBorder()).
BorderForeground(lipgloss.Color("240")).
BorderBottom(true).
Bold(false)
s.Selected = s.Selected.
Foreground(lipgloss.Color("229")).
Background(lipgloss.Color("57")).
Bold(false)
t.SetStyles(s)
m := model{t}
if _, err := tea.NewProgram(m).Run(); err != nil {
fmt.Println("Error running program:", err)
os.Exit(1)
}
}
これを動作させると
画面いっぱいに表示されます。
Bubble Teaのターミナルアプリでは、画面のサイズがわかると
tea.WindowSizeMsg
というメッセージが送られてきます。このメッセージに反応してテーブルのサイズとカラムのサイズを調整しています。
新しいテーブルの幅に合わせて、元のカラム幅の割合で計算しています。
ターミナルのWindowをリサイズすると
のようにテーブルもリサイズできます。
余談
この他ターミナルアプリのテーブル表示は
の開発で使っています。