WebAssembly Advent Calendar 2024 の 10 日目の記事です。
この記事では、WebAssembly をリアルワールドで実用的に活用している Zellij について紹介したいと思います。
Zellij について
Zellij はいわゆる tmux や screen などのターミナルマルチプレクサの機能をもつ Rust でかかれた “terminal workspace” です。
A terminal workspace with batteries included
ターミナルエミュレータ上で端末セッションの管理やタブ・ペインといった操作を加え、コマンドライン環境を強力にサポートしてくれます。
同様の機能を有する tmux は時間を使ってコンフィグレーションし使い方を身につける必要がありますが、Zellij は操作ガイドも常に表示することもでき、瞬間的に導入できるお勧めのターミナルマルチプレクサとなっています。
Zellij と WebAssembly
Zellij は一般的なターミナルマルチプレクサの機能に加え、WebAssembly によるプラグインシステムを持っており、任意の Wasm 対応のプログラミング言語で機能の拡張が可能です。具体的には、
- ホットキーからペインを開き UI 含めた任意の処理を実行。
- レイアウトに常に表示する情報ペインを実装。
- パイプから入力された文字列処理して戻す。
などなどの処理を Wasm でかいたプログラムをもって実行できます。
プラグインは.wasm
バイナリとして配布され、Zellij から実行時にダイナミックに読み込まれ内部の wasmtime ランタイムで実行されます。
このことから、amd64 や aarch64、riscv64(つまり各種 Linux や macOS)などのプラットフォームを気にせず、同一のプラグインバイナリを安全に動作させることができて非常に便利です。
プラグインの API は次のようになっています。
Rust の例:
use zellij_tile::prelude::*;
#[derive(Default)]
struct State {
}
register_plugin!(State);
impl ZellijPlugin for State {
fn load(&mut self, configuration: BTreeMap<String, String>) {
// ...snip...
}
fn update(&mut self, event: Event) -> bool {
let mut should_render: bool = false;
// ...snip...
should_render
}
fn render(&mut self, rows: usize, cols: usize) {
}
}
WebAssembly プラグインであるのに関わらず、引数のシグネチャが非常にリッチな形になっているのが確認できますが、これは Protocol Buffers の仲介をもって ABI の安定化がされています。
https://github.com/zellij-org/zellij/tree/main/zellij-utils/src/plugin_api
将来的には Component Model / WIT になるのかもしれませんが、現在用いることができるインターフェース手法のひとつとして個人的にとても参考になりました。
Zellij プラグインはお気に入りの言語でプラットフォームを気にせず思いついたアイディアをすぐ実装できて楽しいのではないかと思いますので、Wasm プレイとしても良ければ…!
https://github.com/zellij-org/awesome-zellij
A list of resources for Zellij workspace: plugins, tutorials and configuration settings.
というわけで、Wasm でお手軽に拡張できる Zellij の紹介でした。- 最後にいくつか自分がつくったプラグインを貼り付けて記事を終わりたいと思います。
zellij-datetime – WASI から現在時刻をシステムインターフェースし、タイムゾーンを選択して表示
zellij-imagebox – パイプから画像バイナリをもらって、いい感じにリサイズ・減色して sixel graphics でペイン上に出力