Ghostty 開發日誌 004
哈囉!歡迎來到 Ghostty 的第四篇官方開發日誌 👻!
如果你錯過了之前的開發日誌,或是想更了解 Ghostty 是什麼,請參考本網站上的 Ghostty 頁面。
社群動態
上週,我分享了我們的公開 Discord 伺服器,也發表了一場關於 Ghostty 與 Zig 的演講。如果你錯過了其中任何一個,請務必去看看。我會透過 Discord 社群發放新的 Beta 測試邀請。另外,我們的 Discord 社群已經成長到超過 600 人。哇!
自上一� Ghostty 開發日誌以來,封閉測試的人數已從約 30 人成長到約 100 人。在專案初期,每一波新的測試邀請只有少數幾人,但隨著 Ghostty 變得越來越穩定,我們現在每一波都能輕鬆地增加 15 到 20 名封閉測試成員。我認為這是一個非常好的跡象!
精美的圖形介面
在深入探討終端機內部運作與古老的技術之前,讓我們先來談談圖形介面的改進,並欣賞一些賞心悅目的畫面。如果你想看深入的技術內容,後面的章節會深入探討許多細節。
macOS 與 Linux 上的原生圖形介面都有了大幅的進展。在 Linux 上,Ghostty 現在擁有標頭列選單、寬版分頁(可設定)、關於視窗等更多功能。與 Gnome Terminal 及其他基於 GTK 的終端機並排時,Ghostty 完全融入其中:

另外在 Linux 上,我們現在有多位 Beta 測試者透過 Sway、Hyprland 及其他合成器使用 Wayland。我們修復了不少問題,Ghostty 現在在 Wayland 上運作得非常順暢。
在 macOS 上,我們新增了 window-theme 設定,讓你可以將 Ghostty 永久設定為深色或淺色模式,而不只是跟隨系統設定。我個人在 macOS 上使用淺色模式,但我的終端機永遠是深色的,所以我可以強制設為深色。我們也讓未取得焦點的分割視窗會呈現淡化效果(此功能可設定)。整體看起來非常漂亮:

Ghostty 的既定目標之一,就是提供原生體驗,讓人感覺 Ghostty 是專為你所使用的平台量身打造的。我們非常重視圖形介面的改進,並確保 Ghostty 遵循其運行平台的慣用設計。上述的改進展現了我們在這些理念上的進展。
我們發現了一個 Vim 的錯誤!還有其他不乖的程式。
在 Ghostty 大部分的生命週期中,它都將自己標示為 TERM=xterm-ghostty。xterm- 前綴的存在,是因為許多不乖的程式會對 TERM 進行字串比對,以判斷終端機是否支援某些功能。這是錯誤且非常不乖的做法,請不要這麼做!正確的做法是查詢 terminfo(終端資訊)資料庫。
terminfo 本身就是一個極其有趣(主要是因為它非常棘手)的題目。我希望有一天能寫一篇專門介紹 terminfo 的部落格文章。這篇開發日誌不會深入探討 terminfo。如果你想一窺這個古老怪獸的面貌,請在你的終端機中執行 infocmp。
在過去一個月裡,我們一直試圖擺脫 xterm- 前綴,直接成為 TERM=ghostty。在這個過程中,我們發現了自身 terminfo 資料庫中的許多錯誤,以及上游的問題。我們正一邊進行一邊修復兩者。
最近,我們被一個vim 錯誤卡住了。Vim 9.0 支援 Kitty Keyboard Protocol(Kitty 鍵盤協定),但它寫死了支援該協定的終端機清單,並未正確遵從 terminfo 資料庫。這是一個錯誤,而一位 Ghostty 社群成員令人驚艷地已經提交了一個 pull request 來修復它。這個問題不會影響 Neovim。
Vim 只是一個有那麼一點點重要的軟體1,因此在該錯誤被修復且下游發行版廣泛更新之前,我們很遺憾地不得不恢復為 TERM=xterm-ghostty。儘管如此,我仍為我們取得的進展感到自豪,並樂觀地認為我們很快就能掙脫 xterm 的束縛。
我們還發現了其他上游的錯誤,我很自豪 Ghostty 社群不僅回報問題,還提供了修復。Tim(提姆·卡爾弗豪斯)向熱門的 Go 函式庫 tcell 提交了一個 PR,以修復一個特別嚴重的問題。這是一個重要的函式庫,因為它被許多熱門的 TUI 應用程式所使用,例如 lazygit、lazydocker 等。如果沒有這個修復,除非你明確地以 TERM=xterm-256color 執行,否則所有這些程式都會吐出一堆亂碼。希望這個修復能盡快被接受!
這些錯誤或修復都不是 Ghostty 特有的,所有的修正都應該能讓程式在面對所有不熟悉的終端機模擬器時變得更加穩健。
這項工作主要由提姆·卡爾弗豪斯推動,我對他在此所做的一切深表感激。
XTGETTCAP (#563)
terminfo 的一大問題在於它依賴一個本機檔案,而正在執行的程式必須去檢查它。這意味著如果你透過 SSH 連線到遠端主機,而遠端主機沒有你終端機的 terminfo,程式就無法判斷你的終端機具備哪些能力,可能會出現錯誤或非最佳的行為。
XTGETTCAP 是終端機的一項功能,它允許透過 VT 跳脫序列來查詢終端機的 terminfo 資料庫,而非讀取本機檔案。這有幾個好處:程式不需要知道如何解析二進位格式或查找檔案路徑,而且即使程式是在遠端執行,也能查詢 terminfo。
XTGETTCAP 看起來像這樣:
# Query for stylized underline support (key "Smulx")
ESC P + q 536D756C78 ESC \
# Response from the terminal (Smulx=\E[4:%p1%dm)
ESC P 1 + r 536D756C78=5C45343A25703125646D ESC \完全一目了然,對吧?其實也沒那麼糟。程式會傳送文字 ESC P + q <key> ESC \,其中 <key> 是經過十六進位編碼的字串。在上面的範例中,我們將「Smulx」進行了十六進位編碼。而回應則包含了該 terminfo 項目的鍵與值,同樣是經過十六進位編碼的。
我們實作中一個特別酷的地方是,我們利用了Zig 的 comptime 能力,在編譯時期產生所有可能的請求與回應。這是從與產生我們實際 terminfo 檔案相同的來源檔案所產生的,因此我們的 terminfo 和 XTGETTCAP 永遠保持完美同步。
XTGETTCAP 的效能其實一點也不重要,但我們的 XTGETTCAP 實作快得離譜,因為它是一個在編譯時期最佳化的查詢表。我們不需要進行任何記憶體配置、字串格式化等操作。我們只需做一次簡單的查詢,找到一個穩定的字元指標,然後直接將其寫入 pty。非常酷。
請看看產生這些內容的 Zig 程式碼片段。我愛 Zig 的 comptime。
Variable Fonts(可變字型) (#345)
大多數字型提供一組固定的樣式,例如「Bold」、「Heavy」、「Medium」、「Italic」等。另一方面,Variable Fonts 則提供單一的字型外觀,讓 weight、slant 等各種軸向可以透過某個範圍內的連續數值來設定。Ghostty 現在已支援 Variable Fonts 以及變體軸向的設定。
首先,讓我們來看看 Variable Fonts 是什麼樣子。Inconsolata 有一個 Variable Fonts 版本,你可以在下方的影片中看到我如何精細地控制字元的寬度與粗細。
以下是 Ghostty 使用 Inconsolata 時的預設外觀,未設定任何字型變體軸向:

而以下是我們稍微調整了粗細的設定。差異很細微,但你可以看到。先是設定檔,接著是螢幕截圖。
font-family = Inconsolata
font-variation-bold = wght=500

為什麼上面用的是 wght 而不是 weight?變體的鍵是由字型本身決定的,且字型變體必須為四個字元。這些並未標準化,因此我們無法安全地將 weight 轉換為 wght。Ghostty 的設定使用字面上的變體鍵,使用者可以使用任何字型檢測程式(例如 FontDrop)來確定有效的鍵。
在終端機模擬器中,對 Variable Fonts 的支援相對少見,因此我很自豪我們支援了這項功能(而且是跨平台的!)。這類功能真的能讓你將終端機微調到完全符合你想要的樣子,讓它感覺恰到好處。
結語
再次感謝我們最新一輪的 Beta 測試者。每一輪總是會帶來一些非常出色的人,他們擁有某些專業領域的深厚知識,或是以新穎、獨特的方式使用終端機來找出問題。
如果你想掌握最新動態,請在 Twitter 或 Mastodon 上追蹤我(連結在頁尾)。這個部落格也有提供RSS 訂閱。
Boo. 👻
註腳
願 Bram Moolenaar(布拉姆·莫倫納爾) 安息,感謝你為我們付出的一切。↩
隨機一篇部落格