Libghostty Is Coming

Mitchell Hashimoto

libghosttyがやってくる

2年以上前、Ghosttyについて行った初期の公開トークのひとつで、私はlibghosttyの構想を語りました。あらゆるアプリケーションが、完全に機能するモダンで高速なターミナルエミュレータを組み込める、埋め込み可能なライブラリというアイデアです。libghosttyはようやく形になり始め、その計画の詳細をお伝えできることを嬉しく思います。

最初のlibghosttyライブラリはlibghostty-vtになる予定です。ターミナルシーケンスのパースとターミナル状態の維持を行うAPIを提供する、依存関係ゼロのライブラリで、実戦で証明されたGhosttyのコアから直接抽出されたものです。なんとlibcすら必要としません!

ご注意:この記事は主にlibghosttyのロードマップのアップデートであり、最初に出荷予定のコンポーネントについての発表です。Zig APIは現在テスト用に利用可能ですが、C APIはまだ準備ができておらず、間もなく公開予定です。いずれも初期テスト段階の品質であり、一般利用にはまだ適していません。


なぜlibghosttyなのか

まずは、なぜlibghosttyが必要だと私が考えるのか、その背景からお話しします。

何らかの形でターミナルエミュレーションを実装しているプログラムは、何百も存在します。最もわかりやすいのは、GhosttyやKitty、iTerm2といった汎用のターミナルエミュレータそのものです。しかし、tmuxzellijのようなターミナルマルチプレクサも、完全なターミナルエミュレータなのです!1 また、JetBrains製品向けのjediterm、VS Code向けのXterm.js、Zedで使われているAlacrittyなど、エディタも独自のターミナルエミュレータを内蔵しています。

完全なターミナルエミュレータに加えて、多くのウェブサイトやアプリケーションが、ログやコマンドの出力を表示するために読み取り専用のターミナルエミュレーションを実装しています。例えば、GitHub Actionsの出力は単純なカラーシーケンスをパースします(それ以外はほとんどしません)。また、VercelやRenderのようなホスティングプロバイダも、ビルドログ内で行のクリアや再描画、色のパースを可能にするシンプルなターミナルエミュレーションを実装しています。

これらの実装の多くは、その場しのぎの一回限りの対応です。共通のライブラリやコードベースを使っているわけではありません。2 ターミナルエミュレーションは、一見すると単純に見える古典的な問題ですが、予期せぬ複雑さやエッジケースだらけです。3 その結果、ほとんどの実装は不完全で、バグがあり、動作も遅くなっています。4

正確さの問題を別にしても、何らかのターミナルエミュレーションを実装すること自体が、ほとんどの開発者にとって時間の無駄です。ターミナルエミュレーションは、JetBrainsやVisual Studio Code、GitHub、Vercel、Renderなどにとって本業ではありません。どこでも一貫して使える、安定した再利用可能なソリューションがあれば、彼らにとって大きな利点になるはずです。

これに対する私の答えがlibghosttyです。クロスプラットフォームで依存関係を最小限に抑え、C APIを公開することで、機能豊富で正確、かつ高速なターミナル機能を、あらゆるアプリケーションがどこでも組み込めるようにするライブラリです。


始まり:libghostty-vt

最初のlibghosttyライブラリはlibghostty-vtです。依存関係ゼロ(libcすら不要)のライブラリで、ターミナルシーケンスのパースと、カーソル位置や現在のスタイル、テキストの折り返しなどを含むターミナル状態の維持を行うAPIを提供します。

ターミナルシーケンスのパースは、ターミナルエミュレータの中核となる最も基本的な機能であり、Ghosttyのような完全なターミナルエミュレータから、GitHub ActionsやVercelのビルド出力のようなスタイルのみを表示するシンプルな読み取り専用ビューまで、あらゆる場面で必要とされます。

状態遷移図は一見すると比較的シンプルに見えるかもしれませんが、正確に実装するのは意外なほど困難です。例えば、Jeditermは中間バイトを正しく扱えていません。そのため、この記事の執筆時点では、広くサポートされている「カーソル形状を変更する」シーケンスが、すべてのJetBrains製エディタで1文字を飲み込んでしまうという問題が起きています。

スタイルのみのパースでは、多くの開発者が完全な状態遷移図をスキップしてしまいます。代わりに軽くウェブ検索をして、\e[31\e[41mのような単純なANSIシーケンスだけをパースして「カラー対応」を謳います。しかし、スタイル関連のシーケンスはそれよりはるかに複雑で、例えばRGB指定だけでも十数種類のフォーマットが存在します。そして、この複雑なスタイルシーケンスを正しくレンダリングできるウェブコンソールを、私はまだひとつも見つけられていません。5

libghostty-vtは、こうした問題すべてを解決することを目指しています。

libghostty-vtはGhosttyから抽出されたもので、実戦で得られたすべての利点を受け継いでいます。SIMDによる最適化されたパース、非常に優れたUnicodeサポート、高度に最適化されたメモリ使用量、ファジングとValgrindで徹底的にテストされた堅牢なコードベース、Kitty Graphics ProtocolやTmux Control Modeのパースといった優れた機能互換性など、数多くの特徴を備えています。

これらすべてが、依存関係ゼロ(libcにすら依存しない)の単一のC APIとしてパッケージ化されており、あらゆる主要な言語エコシステムに簡単に組み込めるようになっています。

フットプリントが非常に小さいため、libghostty-vtは高い移植性を備えています。初期ターゲットは、Ghosttyアプリケーションの主要ターゲットでもあるmacOSとLinuxの、x86_64aarch64の両アーキテクチャです。ただ、今後はWindowsや組み込みデバイス、WASMによるウェブなど、対応ターゲットをさらに広げていく予定です。スコープがより絞られている分、libghosttyはGUIとしてのGhosttyよりも幅広い環境をサポートすることになります。


長期的な展望

libghostty-vtはあくまで始まりに過ぎません。長期的には、さらなるlibghostty-<x>ライブラリを提供し、入力処理(キーボードエンコーディングは大きな課題のひとつです)、GPUレンダリング(OpenGLやMetalのサーフェスを渡していただければ、残りは私たちが対応します)、ターミナルビュー全体を担うGTKウィジェットやSwiftフレームワークなど、追加の機能を公開していく予定です。

基盤となる部分が安定するにつれて、提供する機能をどんどん増やしていきます。これらは、依存関係やコードサイズ、そして全体的なメンテナンスの複雑さを最小限に抑えるため、一連のライブラリ群として構成される予定です。


libghostty-vtの現状

先ほど、libghostty-vtをZigモジュールとして公開するプルリクエストをマージしました。このPRには最小限のサンプルプログラムも含まれています。Zigの開発者であれば、すぐにlibghostty-vtを試すことができます。

C APIはまだ準備ができていませんが、現在まさに取り組んでいるところで、間もなくテスト用に公開される予定です。必要な作業はC APIの定義だけで、コアとなるロジック自体はもちろんすべて揃っており、何年もGhosttyで使われてきたものです。加えて、GhosttyのmacOSアプリはすでに内部専用のC APIを利用しています。

もし内部専用のCヘッダをご覧になっても、その雑多な内容はご容赦ください。決して良いC APIとは言えません。あくまで内部専用で、macOSアプリケーションの要件を満たすために存在しているものです。これは一般向けに利用できるlibghosttyではありませんが、すでに実際の商用製品でGhosttyの組み込みに使われています。より広く使っていただくためのC APIは、ゼロから新たに設計し直す方針です。

libghosttyは、アプリケーションとしてのGhosttyとは別にバージョン管理する予定です。このブログ投稿をもって公開アルファ版(APIの安定性は保証しません)と位置づけ、C APIの準備が整い次第、ぜひ多くの開発者の方に使っていただき、いずれは各言語向けのバインディングを書いていただければと期待しています。

今後6か月以内にタグ付けされたバージョンのlibghostty-vtをリリースしたいと考えていますが、準備が整うかどうか次第です。


フィードバックをお待ちしています

私たちは今、libghosttyのAPIを設計するという極めて重要な段階にいます。そしてAPIを設計する最良の方法は、実際に使ってくれる方々からのフィードバックを得ることです。Ghostty自体がひとつの利用者であり、他にもコミュニティのメンバーがlibghosttyを利用するプロジェクトに取り組んでくれていますが、できるだけ多くの声をいただきたいと思っています!

もしご自身のプロジェクトや組織でlibghosttyの使い道が思い浮かぶ場合は、ぜひGhosttyのDiscordに参加して、開発に携わるメンバーと一緒に議論してください。Discordへの参加を希望されない場合は、私までメールでご連絡ください(メールアドレスはこのサイトのフッターに記載しています)。

ここでいう「アルファ」品質とは、API(関数や型)自体に関するものです。コアロジックはGhosttyと共通で、実戦で証明された極めて安定したものとなっています。


次のフロンティア

アプリケーションとしてのGhosttyがようやく安定し、libghosttyという目標に向けて動き出せる段階に来たことを、とても嬉しく思っています。libghosttyはGhosttyにとって次のフロンティアであり、単体のアプリケーションとしてのGhosttyを超える、はるかに大きなインパクトを与える可能性を秘めていると考えています。

ご安心ください。アプリケーションとしてのGhosttyについても、まだまだ多くの変更を予定しており、これによって私の熱意や計画が損なわれることはありません。libghosttyがより広く使われることで、Ghostty自体もlibghosttyの利用者であるため、より高機能で安定したGhosttyアプリケーションにつながっていきます。

Boo. 👻

脚注

  1. これらは子プロセスに対してptyを所有し、すべてのエスケープコードをパースし、スクリーン状態を管理し、最終的には親のターミナルエミュレータに対して独自のエスケープコードを出力することで「レンダリング」します。

  2. 多くのウェブサイトではXterm.jsが使われており、GTKエコシステムにはlibvteがあります。しかし、これらがカバーしているのは全体のごく一部に過ぎず、前述の例もそれぞれスコープが限られています。

  3. 私は3年近くターミナルエミュレーションに取り組んできましたが、今でも奇妙なエッジケースが見つかり続けています

  4. 影響の大きい問題の実際の例をいくつか挙げます。Jeditermが中間バイトを正しく処理できていなかった例や、AppleのTerminal.appがDCSシーケンスをそのまま出力に流してしまう例などです。特定の誰かを非難する意図はなく、こうした問題が存在すること、そしてターミナルエミュレーションを正しく実装するのがいかに難しいかを示すための例です。

  5. 多くの汎用ターミナルエミュレータもこれを誤って実装しており、9か月前のGhosttyもそのひとつでした

原文は Mitchell Hashimoto により に公開されました。

この記事は「muse-spark-1.2-contributor」を使用して翻訳されました。