Ghostty Devlog 005

Mitchell Hashimoto

Ghostty 開発ログ 005

原文は Mitchell Hashimoto により に公開されました。 このブログを購読する

こんにちは! Ghostty 👻 の公式開発ログへようこそ!

前回の開発ログから2ヶ月以上が経ちましたが、その間に Ghostty にはたくさんのアップデートがありました。新米パパとして忙しくしていたのと、パソコンに向かえる自由な時間はほとんど Ghostty の改善に費やしていたので、開発ログの方が少しおろそかになってしまいました。すみません!

これまでの開発ログを見逃した方や、Ghostty が何なのかもっと知りたい方は、こちらの本サイト内の Ghostty ページをご覧ください。


コミュニティアップデート

この2ヶ月で、ベータテストグループは100人から350人以上に増えました!すごい!2ヶ月前は50人にも満たなかったのに。こんなターミナルプロジェクトに興味を持っていただき、そして参加してくれているベータテスターの皆さんには心から感謝しています。これだけ大きく、さらに拡大し続けるテスターの皆さんのおかげで、公開リリースを迎える頃には Ghostty は堅牢で安定したプロジェクトになっているはずです。

毎回のベータ募集でこれだけ人数を増やせるのは、Ghostty がどんどん機能的に完成し、安定してきているからにほかなりません。以前は5人募集するだけで十数件のバグや機能要望が上がっていました。今は50人招待して同じくらいの数です。そしてこの人数は今後さらに増えていくでしょう。プロジェクトがどんどん現実味を帯び、安定していく様子を見るのは本当にやりがいがあります。

ベータプログラムへの参加に興味がある方は、Ghostty Discord に参加してください。次のベータ募集の対象として検討されます。執筆時点で、Discord コミュニティの約20%がベータに参加しています。


ターミナルインスペクタ (#728)

ターミナルはアプリケーションプラットフォームです。「プラットフォーム」という言葉は、自分の仕事を実際以上に重要に見せようとする人たちによって(あるいは少なくとも投資家にそう信じ込ませようとして)使われすぎていると思いますが、ターミナルはまさにテキストベースのインタラクティビティのためのプラットフォームなのです1

ターミナルは、その上で動くアプリケーションがなければ面白くありません。さらに言えば、アプリケーションがなければターミナルは無意味です。ターミナルアプリケーションの数と質を高める一つの方法は、ターミナル向けの開発をより簡単にすることです。

ウェブに目を向けると、私にとって開発のしやすさが飛躍的に向上したのは、Firebug の登場でした。現在ではより一般的に「ウェブインスペクタ」と呼ばれ、同様の機能がすべての主要ブラウザに搭載されています。同じような体験をターミナルにもたらしたいと考え、Ghostty にターミナルインスペクタを導入しました。

ターミナルインスペクタはウェブインスペクタと同様に動作します。ターミナルごとに表示されるパネルで、実行中のターミナルに関する情報がリアルタイムで更新されます。キーボード入力(とそのエンコード方法)、ターミナルモード、フォントサイズ、グリッドサイズ、セルのメタデータ、パレットカラーなど、さまざまな情報を確認できます。

ターミナルインスペクタの目標は、ターミナル開発者にとって不可欠なツールとなり、ターミナルアプリケーション(Ghostty だけでなくあらゆるターミナルで動作するもの)の開発やデバッグを容易にすることです。

ターミナルインスペクタはまだ非常に初期段階で、実験的な機能です。現在は完全に読み取り専用のインターフェースですが、将来的には読み書き可能にして、セルやターミナルモードの変更、合成入力イベントの生成などができるようにする予定です。

ターミナルインスペクタの元々のアイデアはベータコミュニティのメンバーから生まれたもので、私を含むベータコミュニティ内の小さなグループがすぐに集まり、このアイデアを現実のものへと育て上げました。関わってくれた皆さん、ありがとうございます!


アジア言語入力 (#八百八十八)

最近のベータ募集では、より多様なタイムゾーンから参加者を招待するよう意識的に努めました。その結果、中国語、日本語、韓国語といった言語で入力するテスターが大幅に増えました。彼らからアジア言語の入力や描画に関する問題が10件近く報告され、そのおかげで Ghostty はこれらの言語で非常に良好に動作するようになりました。

開発ログ 003では「キーボード入力の処理はあなたを苦しめる」というタイトルでキーボード入力に特化したセクションを書きました。その中で Ghostty がいかに素晴らしく動作するか大口を叩きましたが、今回はそれをさらに強調し、すべてがいかに恐ろしく複雑であるかを改めて述べた上で、Ghostty はそれらすべてを見事に処理していると断言したいと思います2

より複雑な入力状態

開発ログ 003ではデッドキー状態という概念を紹介しました。当時の Ghostty は単一のコードポイントに対するデッドキー状態を処理していました。例として挙げたのはアクセント付きの英字で、'(アポストロフィ)のような文字を入力した後に a のような文字を入力すると á になるというものでした。

日本語のような言語では、何文字か入力すると変換候補が表示され(候補のドロップダウンが表示されることもあります)、Enter や Tab などのキーを押して候補を確定します。

Ghostty は複数コードポイントにわたる変換候補を処理できておらず、変換候補の表示中に Enter や Tab などの文字を誤って処理していました。これらはすべて修正され、現在は日本語(および他の言語)を入力できるようになっています。

この複数コードポイントの候補状態は、行末での入力や、狭すぎるウィンドウでの入力といったいくつかのエッジケースも引き起こしました。これらも現在は Ghostty で適切に処理されています。なお、上の動画は別のバグが修正される前に収録されたものですが(見つけられるでしょうか)、そのバグも現在は解消されています。

中国語文字の配置 (#982)

等幅のターミナルグリッド上で複数のフォント(さらに絵文字も)をきれいで統一感のある見た目で描画することは難しく、中国語の文字が少し正しく表示されていませんでした。

で始まる単語が少し低めに描画されているのが分かるでしょうか。これは特定のフォントを混在させた際に、フォントメトリクスの計算(この場合はセルのベースライン)が間違っていたことが原因でした。これは現在 Ghostty で修正されています。

Linux での IME 入力 (#919)

macOS は OS に組み込まれたインプットメソッドエディタ(IME)のサポートが非常に優れています。GTK を使った Linux では、IME はオプションでインストールされるプラグインとして提供されます。そのため Ghostty では十分にテストされておらず、中国語、日本語、韓国語ではまったく動作していませんでした。

幸い、Ghostty の共通コアで IME をサポートするための作業をかなり進めていたので、Linux でこれを正しく動作させるために必要だったのは、適切な GTK と Ghostty の API をつなぎ合わせるための +47/-1 の差分だけでした。その結果、Linux でも IME が動作するようになりました。

注:この動画は上記の修正が行われる前に収録されたものなので、文字が正しく描画されていない様子が確認できます。


カスタムシェーダー (#903)

ターミナルをクラシックなブラウン管のように、あるいは壊れた VHS テープのように見せたいと思ったことはありませんか?一体何を言ってるんだ、クソ?正気を失ったのか?ともかく、Ghostty ではカスタムシェーダーを指定することで、そういったことも含めてすべて実現できるようになりました。

実用性を脇に置いておくとして、こういった機能はバッテリー持ちに悪そうに見えますよね。現代のソフトウェアの多くが非効率なせいで、みんなそう思い込まされています!CPU も GPU も超高速で、これはほとんど何もしていないに等しいのです。私のマシンでは、上記のエフェクトは CPU を約1%、GPU を約2%しか使用しません。この機能を使わない場合よりは確実に電力を多く消費しますが(もちろん!)、ファンが唸りを上げるようなことは決してありません。

Ghostty は GPU 駆動のターミナルエミュレータです。macOS では生の Metal を、Linux では OpenGL を使用しています。GPU はシェーダーを呼び出すことで描画を行います。シェーダーとは手をひらひらさせながら言うと、GPU 上で実行されるプログラムのことです。

シェーダーは一般的に技術ごとに固有のプログラミング言語で記述されます。例えば macOS の Metal は MSL(Metal Shading Language)を、OpenGL は GLSL(GL Shading Language)を使用します。Ghostty は GLSL で書かれたシェーダーを受け付け、macOS ではそれをオンザフライで MSL に変換します。そのために Ghostty は glslang を使って GLSL を SPIR-V(大まかに言えば中間表現)に変換し、さらに SPIRV-Cross を使って SPIR-V を MSL などのターゲットフォーマットに変換しています。これらのツールは公開されている C API を使ってコンパイルし、バインドしています。

この機能のさらにクールな点は、Ghostty が Shadertoy のインターフェースを公開していることです。そのため、多くの Shadertoy シェーダーをそのまま Ghostty に持ち込んで使うことができます。さらに重要なのは、Shadertoy 自体を Ghostty のカスタムシェーダー用のライブでインタラクティブな開発ツールとして使えることです!

ご安心ください、この機能がパフォーマンスに悪影響を与えることはありません。Ghostty はマルチスレッドのレンダリングアーキテクチャを採用しており、フレーム間には十分なアイドル時間があります。カスタムシェーダーを使用している場合、アイドル時間は減りますが、他のスレッド(IO や GUI)への影響はほとんど、あるいはまったくありません。カスタムシェーダーを使用していない場合、Ghostty は従来と同じレンダリングパイプラインを使用し、既存の実行に新たなリソースを追加することもありません(カスタムシェーダーの有無をチェックする1つの真偽値と、空のカスタムシェーダーリストを表す最小限のメモリフットプリントを除いて)。

でも、これって完全に無意味なんじゃないの? 最も一般的なユースケースは楽しむためで、それは確かに必須ではありません(ええ、楽しさなんてクソくらえ、ですよね?)。しかし、カスタムシェーダーの主な実用的なユースケースはアクセシビリティです。カスタムシェーダーは、特定の色覚異常への対応、コントラストや明るさを調整して読みやすくすること、「虫眼鏡」エフェクトの作成などに非常に有効な手段となります。

アクセシビリティを他人任せにしようとしているわけではなく、さまざまなアクセシビリティ機能を正式な機能として提供することにも前向きですが、これは Ghostty がまだ特定の機能を備えていない状況で、ユーザーが自分自身で対処するための素晴らしい手段となります。


Xterm 互換性監査と挙動のドキュメント化 (#632)

ターミナルエミュレータはエミュレータですが、一体何をエミュレートしているのでしょうか?伝統的に、ターミナルエミュレータは VT52、VT100、VT220 などの物理的な端末をエミュレートしていました。しかし実際には、このようなハードウェアが容易に入手できたり実用的に使われたりしなくなってから非常に長い時間が経っており、ほとんどの現代的なターミナルエミュレータは単にお互いの挙動を真似しているだけです。そのため、異なるターミナルエミュレータ間で挙動が完全には一致しないことが多々あり、多くのターミナルエミュレータがエッジケースでバグを抱えています3

xterm は X Window System の標準的なターミナルエミュレータであり、歴史的なターミナル挙動のゴールドスタンダードとしてしばしば称賛されています。さらに、xterm は十分に広く使われているため、歴史的な端末を度外視しても、サポートしている機能に関してはその挙動が事実上の標準とみなすことができます。

私は、可能な限りそして合理的な範囲で、Ghostty は xterm の挙動に正確に合わせるべきだと決めました。これにより「なぜ <feature> はこのように振る舞うのか?」という問いに対して、プロジェクトとして一貫した答えを持つことができます4

「可能な限りそして合理的な範囲で」とはどういう意味でしょうか?それは、機能を実装する際にデフォルトとして xterm に合わせるべきだということです。何らかの機能でバグが報告された場合、私たちは常に「この状況で xterm はどう振る舞うか?」と問います。そこから逸脱すべき説得力のある論拠がある場合にのみ、それは例外として扱われ、原則とはなりません。

これを実現するために、xterm の文書化されているすべての機能を一つひとつゆっくりと監査し、Ghostty と比較し始めました。その過程で、できる限り詳細になるよう独自のドキュメントも整備しています。そのドキュメントには、期待される出力とともにシェルスクリプトによる検証ケースも含まれており、互換性を保証するためのエンドツーエンドテストを作成できるようになっています。見た目はこんな感じです:

ターミナルは多くの機能をサポートしており、xterm のコードベースは複雑で、この作業は非常に地道なため、一晩で終わるものではありません。しかしこの数ヶ月で、一つひとつ着実にチェックを進めてきた結果、Ghostty では数十件のバグが修正され、他のターミナルでも数十件のバグが見つかりました(いくつかは報告済み、残りは後日報告予定ですが、いずれも致命的なものではありません)。

これは Ghostty が xterm のサポートするすべての機能をサポートするという意味ではありません。そうではなく、Ghostty が備えている機能のうち xterm がサポートしているものについては、Ghostty は xterm との最大限の互換性を目指すということです(十分な理由があれば例外も認められます)。


おわりに

開発ログでは、私が面白いと思い共有したいと感じた一握りの変更に焦点を当てています。開発ログは変更履歴ではなく、単なる退屈な変更点の羅列のように読まれてほしいとは思っていません。とはいえ、この2ヶ月で Ghostty プロジェクトでは100件以上のバグ修正と改善が行われ、Ghostty は日々着実に公開の準備が整いつつあることも強調しておきたいと思います。

ベータが拡大するにつれ、コントリビューターの数も増えました。Ghostty にはすでに50人近くがコントリビュートしており(ベータテスターの6人に1人近くが、バグ報告だけでなくコードも寄せてくれています!)、本当に素晴らしいことです。プロジェクトに費やしていただいた時間と関心に、心から感謝しています。

最新情報を追いたい方は、Twitter や Mastodon で私をフォローしてください(リンクはフッターにあります)。このブログには RSS フィードもあります。

Boo. 👻

脚注

  1. 投資家を探しているわけではありません。この段落をそのように解釈する人がいないことを願っていますが、そう言っておく必要があると感じました。そしてこれは「いやいや、探してないよ(ウィンク)」という意味ではありません。本当に興味がないのです。

  2. 入力の処理は複雑で、まだバグが残っているのは確かですが、現在は日本語、韓国語、中国語を話すベータテスターが Ghostty をフルタイムで使える状態になっています。

  3. のような幅広文字を分断するエスケープシーケンスを適切に処理できているターミナルエミュレータはほとんどありません。仕様が存在しないため、ここで言う「適切に」は議論の余地があります。つまり、彼らは好きなように振る舞えるとも言えます。別の言い方をすれば、挙動はきわめて一貫性がありません。

  4. これはもちろん xterm が実装している機能にのみ当てはまります。Kitty Graphics Protocol のような機能は Kitty によって明確に定義されており、その場合は可能な限り Kitty に正確に合わせるようにしています。

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

コメント