自作ツールの gomi をアップデートをした
昔、gomi というターミナルにゴミ箱の概念を実装する CLI コマンドを作っていたのだが、久しぶりに土日を使ってガッツリ書き換えた。ファイルをゴミ箱に移動したり戻したりするという根幹の機能は変えず、UI 部分だけを更新した。
これまでは UI の実装に promptui を使っていた。しかし、Ctrl+W(単語の削除)ができなかったり、Ctrl+C で interrupt した際に UI が崩れたり、そもそも開発がしばらく止まっていたりと、ずっと気になっていた。そんな中、最近 bubbletea (Bubble Tea)1 というイケてる UI ライブラリを見つけてしまい、めんどくさい半分、興味半分で置き換えてみた。
Bubble Tea は Elm Architecture(TEA: The Elm Architecture) が採用されたフレームワークだ。Elm Architecture とは、関数型プログラミングの概念を取り入れたフロントエンドの設計パターンで、シンプルで管理しやすい UI の構築を目的としている。もともとは Elm という言語で使われているが、React や Redux の設計にも影響を与えているらしい。
Elm Architecture とは
Elm Architecture は、主に以下の3つの要素で構成される。
要素 | 役割 |
---|---|
Model | アプリのステート管理をする |
Update | UI 操作や Message を受け取り、Model を更新する |
View | Model から UI を描画する |
Elm では View の戻り値として HTML を返すが、Bubble Tea では文字列を返す。見てのとおりシンプルで、実装者は Model(ステート)を介して Update(処理)と View(見た目)を実装するだけでよく、データの流れは Runtime に任せればいい。View の処理が終わると、Runtime によってレンダリングされ、次のサイクルが動く。
Bubble Tea では Model
という interface で以下のメソッドを定義し、Elm Architecture を表現している。
- Init()
- 初回の Message を送信し、サイクルをスタートさせる。
- Update()
- Message(キー入力などのイベント)を受け取り、適切な処理を行い、新しい Model を返す。
- View()
- 出力する文字列を組み立てて String を返す。
Model
interface を満たす構造体 model
を作成し、Update()
と View()
、およびそれらを行き来する Message
を実装していく流れだ。
キー入力やデータの変更など、いわゆるイベントは Message
と呼ばれており、これを受け取った Update
はそれに応じた処理を行い View
を呼ぶ。Quit
(サイクルの終了)処理などもユーザーが実装する部分なので、Bubble Tea は基本的に Update ←(Model)→ View をひたすら繰り返すというわけだ。
今回、初めて Bubble Tea を使ってターミナルアプリを書いてみたが、Elm Architecture のおかげでスッキリと書けた。また、初学の際は @motemen さんのブログが参考になった。
振り返り
久しぶりの実装はめんどくさかったが、結果的に満足のいく仕上がりになってよかった。ちなみに、gomi の初のリリースは 2015 年らしい。あの頃はまだ大学生だったが、10 年経ってもまだいじっているとは、我ながら物好きだなと思う。
実は UI の書き換えはこれで 2 回目で、初代 UI2 と二代目 UI3 がこんな感じ。こうして振り返ると、今回は結構いい感じに仕上がったのではないかと思う。
![三代目UI (2025)](/post/2025/01/29/gomi/demo-3.gif)
三代目UI (2025)
![二代目UI (2020)](/post/2025/01/29/gomi/demo-2.png)
二代目UI (2020)
![初代 UI (2015)](/post/2025/01/29/gomi/demo-1.gif)
初代 UI (2015)
(2025/02/08追記): サイトも更新した。
![Thumbnail](https://storage.googleapis.com/zenn-user-upload/b3b2ba4ffc5b-20250208.png)
Never worry about accidentally deleting important files again. gomi moves them to trash instead of permanent deletion, giving you peace of mind in the command line.
Bubble Tea の Tea は The Elm Architecture からきているのかも ↩︎
コードを見てみたら UI はなんと自前実装で termbox-go を使っていたようだ。まだコードが小さかったときの peco とか fzf を参考に書いたような気がする ↩︎
termbox-go の実装もパクった部分が多くて自分でよくわかってない部分があったのでメンテできなくなっていた。UI は外部に任せたほうがいいなーと思っていて promptui を見つけてからはこっちに乗り換えた ↩︎