TUIとは、テキストユーザインタフェース(Text User Interface)の略で、文字を使ってコンピューターを操作するインタフェースです。
マウスやタッチパネルを使わず、キーボードからコマンドを入力することで、様々な操作を行います。
Go言語のtcellパッケージを用いて、TUIについて見ていくことにします。
余談ですが、tcellパッケージベースで開発されたアプリにMicroやfzf(fuzzy finder)があります。
ターミナル上でコードを書くためのMicroをインストールする
tcellパッケージを使用できるようにします。
今回は例として、~/workspace/tcell_sample/ディレクトリ以下にファイルを作成することにします。
話を進める前に、最新版のGoをインストールするを参考にして、最新版のGoを使用できるようにしておきましょう。
ターミナルを開き、下記のコマンドを実行します。
$ cd ~ $ mkdir workspace $ cd workspace $ mkdir tcell_sample $ cd tcell_sample $ go mod init tcell_sample $ go get github.com/gdamore/tcell/v2
$ micro main.go
でエディタを開き、下記のコードを作成します。
~/workspace/tcell_sample/main.go
package main import ( "github.com/gdamore/tcell/v2" ) func main() { screen, err := tcell.NewScreen() if err != nil { panic(err) } if err := screen.Init(); err != nil { panic(err) } defer screen.Fini() for { screen.SetContent(0, 0, 'H', nil, tcell.StyleDefault) screen.SetContent(1, 0, 'i', nil, tcell.StyleDefault) screen.SetContent(2, 0, '!', nil, tcell.StyleDefault) screen.Show() } }
エディタを閉じ、ターミナル上で、
$ go run main.go
を実行して、
画面が切り替わることを確認しましょう。
コードの詳細を見ていきます。
screen, err := tcell.NewScreen() if err != nil { panic(err) } if err := screen.Init(); err != nil { panic(err) } defer screen.Fini()
上記のコードで、ターミナルからTUIに切り替わる手続きを行います。
最後の行の
defer screen.Fini()
はmain関数(エンドポイント)内の処理が最後まで行われた後の実行の予約になり、スクリーンの終了を予約しておきます。
次の行からの for で囲まれた箇所はイベントループになりまして、tcellでTUIアプリを作る時は設ける必要があります。
今回のコードでは、イベントループ内で Hi! という文字列を同じ場所に何度も出力させるようにしています。
func (b *baseScreen) SetContent(x, y int, mainc rune, combc []rune, st Style)
https://github.com/gdamore/tcell/blob/main/screen.go#L404
今回のコードでは、main関数を終了させる術がありません。
イベントループを抜ける為に
for { screen.SetContent(0, 0, 'H', nil, tcell.StyleDefault) screen.SetContent(1, 0, 'i', nil, tcell.StyleDefault) screen.SetContent(2, 0, '!', nil, tcell.StyleDefault) screen.Show() }
for 内のコードを
for { ev := screen.PollEvent() // イベントを取得する switch ev := ev.(type) { case *tcell.EventKey: switch ev.Key() { // 何のキーが押されたか?を調べる case tcell.KeyEscape: // ESCキーが押されたら終了する return } default: screen.SetContent(0, 0, 'H', nil, tcell.StyleDefault) screen.SetContent(1, 0, 'i', nil, tcell.StyleDefault) screen.SetContent(2, 0, '!', nil, tcell.StyleDefault) } screen.Show() }
に書き換えます。
変更した内容は、何らかのイベントを取得し、イベントの内、キーを押すイベント(EventKey)とそれ以外のイベントに分けます。
受け取ったイベントがEventKeyであった場合は、何のキーを押されたか?を調べ、ESCキーであれば、イベントループを抜けて、main関数を終了させるという処理になります。
追記
サンプルコード集
https://github.com/gdamore/tcell/tree/main/_demos