楽しく機能的でステートフルなターミナル アプリを構築する方法。 Elm アーキテクチャに基づいた Go フレームワーク。 Bubble Tea は、インライン、フルウィンドウ、またはその両方の組み合わせの、単純な端末アプリケーションと複雑な端末アプリケーションに適しています。
Bubble Tea は実稼働環境で使用されており、その過程で追加された多くの機能とパフォーマンスの最適化が含まれています。その中には、標準のフレームレート ベースのレンダラー、メイン レンダラーと並行して動作する高性能スクロール可能領域用のレンダラー、およびマウス サポートが含まれます。
開始するには、以下のチュートリアル、例、ドキュメント、ビデオ チュートリアル、およびいくつかの一般的なリソースを参照してください。
Bubble Tea の一般的な UI コンポーネントのライブラリである Bubbles を必ずチェックしてください。
Bubble Tea は、Elm アーキテクチャの機能設計パラダイムに基づいており、Go とうまく連携します。これはアプリケーションを構築するための素晴らしい方法です。
このチュートリアルは、Go の実用的な知識があることを前提としています。
ちなみに、このプログラムのアノテーションなしのソースコードはGitHubで公開されています。
このチュートリアルでは、買い物リストを作成します。
まず、パッケージを定義し、いくつかのライブラリをインポートします。唯一の外部インポートは Bubble Tea ライブラリ (略してtea
と呼びます) です。
package main
import (
"fmt"
"os"
tea "github.com/charmbracelet/bubbletea"
)
Bubble Tea プログラムは、アプリケーションの状態を記述するモデルと、そのモデル上の 3 つの単純なメソッドで構成されます。
それでは、アプリケーションの状態を保存するモデルを定義することから始めましょう。任意の型を使用できますが、通常はstruct
最も意味があります。
type model struct {
choices [] string // items on the to-do list
cursor int // which to-do list item our cursor is pointing at
selected map [ int ] struct {} // which to-do items are selected
}
次に、アプリケーションの初期状態を定義します。この場合、初期モデルを返す関数を定義していますが、他の場所で初期モデルを変数として簡単に定義することもできます。
func initialModel () model {
return model {
// Our to-do list is a grocery list
choices : [] string { "Buy carrots" , "Buy celery" , "Buy kohlrabi" },
// A map which indicates which choices are selected. We're using
// the map like a mathematical set. The keys refer to the indexes
// of the `choices` slice, above.
selected : make ( map [ int ] struct {}),
}
}
次に、 Init
メソッドを定義します。 Init
初期 I/O を実行できるCmd
返すことができます。現時点では、I/O を実行する必要がないため、コマンドについては、「コマンドなし」を意味するnil
を返すだけです。
func ( m model ) Init () tea. Cmd {
// Just return `nil`, which means "no I/O right now, please."
return nil
}
続いてアップデート方法です。 update 関数は、「何かが起こった」ときに呼び出されます。その仕事は、何が起こったかを調べ、それに応じて更新されたモデルを返すことです。 Cmd
返してさらに多くのことを実行することもできますが、今のところ、その部分については心配する必要はありません。
この場合、ユーザーが下矢印を押すと、 Update
の仕事は、下矢印が押されたことを認識し、それに応じてカーソルを移動する (または移動しない) ことです。
「何かが起こった」は、任意のタイプのMsg
の形式で送信されます。メッセージは、キーの押下、タイマーの刻み、サーバーからの応答など、発生した一部の I/O の結果です。
通常、受信したMsg
のタイプはタイプ スイッチを使用して判断しますが、タイプ アサーションを使用することもできます。
ここでは、キーが押されたときに更新関数に自動的に送信されるtea.KeyMsg
メッセージだけを扱います。
func ( m model ) Update ( msg tea. Msg ) (tea. Model , tea. Cmd ) {
switch msg := msg .( type ) {
// Is it a key press?
case tea. KeyMsg :
// Cool, what was the actual key pressed?
switch msg . String () {
// These keys should exit the program.
case "ctrl+c" , "q" :
return m , tea . Quit
// The "up" and "k" keys move the cursor up
case "up" , "k" :
if m . cursor > 0 {
m . cursor --
}
// The "down" and "j" keys move the cursor down
case "down" , "j" :
if m . cursor < len ( m . choices ) - 1 {
m . cursor ++
}
// The "enter" key and the spacebar (a literal space) toggle
// the selected state for the item that the cursor is pointing at.
case "enter" , " " :
_ , ok := m . selected [ m . cursor ]
if ok {
delete ( m . selected , m . cursor )
} else {
m . selected [ m . cursor ] = struct {}{}
}
}
}
// Return the updated model to the Bubble Tea runtime for processing.
// Note that we're not returning a command.
return m , nil
}
上記のctrl+cとq がモデルでtea.Quit
コマンドを返すことに気づいたかもしれません。これは、バブル ティー ランタイムに終了を指示し、プログラムを終了する特別なコマンドです。
いよいよ、UI をレンダリングします。すべての方法の中で、ビューが最も単純です。現在の状態のモデルを調べ、それを使用してstring
を返します。その文字列が UI です。
ビューにはアプリケーションの UI 全体が記述されているため、ロジックの再描画などについて心配する必要はありません。タピオカティーが代わりに対応します。
func ( m model ) View () string {
// The header
s := "What should we buy at the market? n n "
// Iterate over our choices
for i , choice := range m . choices {
// Is the cursor pointing at this choice?
cursor := " " // no cursor
if m . cursor == i {
cursor = ">" // cursor!
}
// Is this choice selected?
checked := " " // not selected
if _ , ok := m . selected [ i ]; ok {
checked = "x" // selected!
}
// Render the row
s += fmt . Sprintf ( "%s [%s] %s n " , cursor , checked , choice )
}
// The footer
s += " n Press q to quit. n "
// Send the UI for rendering
return s
}
最後のステップは、プログラムを実行するだけです。初期モデルをtea.NewProgram
に渡してリッピングさせます。
func main () {
p := tea . NewProgram ( initialModel ())
if _ , err := p . Run (); err != nil {
fmt . Printf ( "Alas, there's been an error: %v" , err )
os . Exit ( 1 )
}
}
このチュートリアルでは、対話型ターミナル UI の構築の基本について説明しますが、実際には I/O も実行する必要があります。それについて学ぶには、コマンド チュートリアルを参照してください。とてもシンプルです。
タピオカ ティーのサンプルもいくつか用意されており、もちろん Go Docs もあります。
Bubble Tea アプリは stdin と stdout の制御を想定しているため、ヘッドレス モードで delve を実行してから接続する必要があります。
# Start the debugger
$ dlv debug --headless --api-version=2 --listen=127.0.0.1:43000 .
API server listening at: 127.0.0.1:43000
# Connect to it from another terminal
$ dlv connect 127.0.0.1:43000
--listen
フラグを明示的に指定しない場合、使用されるポートは実行ごとに異なるため、これを渡すと、スクリプトまたは選択した IDE からデバッガーを簡単に使用できるようになります。
さらに、下位互換性の理由から、delve のデフォルトはバージョン 1 であるため、 --api-version=2
を渡します。ただし、delve はすべての新規開発にバージョン 2 を使用することを推奨しており、一部のクライアントはバージョン 1 では動作しなくなる可能性があります。詳細については、Delve のドキュメントを参照してください。
TUI が占有しているため、Bubble Tea を使用して標準出力に実際にログを記録することはできません。ただし、バブル ティー プログラムを開始する前に、次のような内容を含めることでファイルにログを記録できます。
if len ( os . Getenv ( "DEBUG" )) > 0 {
f , err := tea . LogToFile ( "debug.log" , "debug" )
if err != nil {
fmt . Println ( "fatal:" , err )
os . Exit ( 1 )
}
defer f . Close ()
}
何がログに記録されているかをリアルタイムで確認するには、別のウィンドウでプログラムを実行しながら、 tail -f debug.log
を実行します。
Bubble Tea で構築されたアプリケーションは 8,000 を超えています。ここではその一部をご紹介します。
Bubble Tea で構築されたその他のアプリケーションについては、「Charm & Friends」を参照してください。タピオカティーで作った何か素敵なもので、シェアしたいものはありますか? PRの方も大歓迎です!
「貢献」を参照してください。
このプロジェクトについてのご意見をお待ちしております。お気軽にメモを残してください。
タピオカ ティーは、Evan Czaplicki らによる The Elm Architecture のパラダイムと、TJ Holowaychuk による優れた go-tea に基づいています。これは、過去の多くの偉大なツァイヒェンオリエンティエテ ベヌツァーシュニッツステレンからインスピレーションを得たものです。
マサチューセッツ工科大学
チャームの一部。
Charm热爱开源 • Charm はオープンソースが大好きです • حنُ نحب المصادر المفتوحة