Ghostty Devlog 004

Mitchell Hashimoto

Ghostty 開發日誌 004

原文由 Mitchell Hashimoto 發布,訂閱此部落格

哈囉!歡迎來到 Ghostty 的第四篇官方開發日誌 👻!

如果你錯過了之前的開發日誌,或是想更了解 Ghostty 是什麼,請參考本站上的 Ghostty 介紹頁面


社群近況

上週,我公開了我們的公開 Discord 伺服器,也發表了一場關於 Ghostty 與 Zig 的演講。如果你錯過了其中任何一個,歡迎去看看。我會透過 Discord 社群發送新的 Beta 測試邀請。而現在,我們的 Discord 社群已經成長到超過 600 人。哇!

自從上一篇 Ghostty 開發日誌以來,封閉測試的人數已從約 30 人成長到約 100 人。在專案初期,每一波 Beta 只會加入少數幾人,但隨著 Ghostty 變得越來越穩定,我們現在每一波都能安心地增加 15 到 20 人。我把這視為一個非常好的跡象!


漂亮的圖形介面

在深入探討終端機內部運作與那些古老的技術之前,我們先來聊聊圖形介面的改進,看看一些賞心悅目的成果。如果你想看更深入的技術內容,後面的章節會鑽得非常深。

macOS 和 Linux 上的原生圖形介面都有了大幅的進展。在 Linux 上,Ghostty 現在有了標題列選單、寬版分頁(可設定)、關於視窗等功能。與 Gnome Terminal 和其他基於 GTK 的終端機並排比較,Ghostty 完全融入其中:

另外在 Linux 方面,現在已有多位 Beta 測試者透過 Sway、Hyprland 等 compositor 在 Wayland 上使用 Ghostty。我們修復了不少問題,現在Ghostty 在 Wayland 上運作得非常順暢。

在 macOS 上,我們新增了 window-theme 設定,讓你可以將 Ghostty 永久設為深色或淺色模式,而不只是跟隨系統設定。我個人 macOS 是用淺色模式,但終端機永遠想維持深色,所以就可以強制設為深色。我們也讓未取得焦點的分割窗格會淡化顯示(此項可設定)。整體看起來非常漂亮:

Ghostty 的目標之一,就是提供原生的使用體驗,讓人感覺 Ghostty 彷彿是為你所使用的平台量身打造的。我們非常重視圖形介面的改進,並確保 Ghostty 遵循各平台慣有的設計風格。上述的改進正是我們在這些理念上進展的展現。


我們發現了一個 Vim 的 Bug!還有其他不乖的程式

在 Ghostty 開發歷程的大部分時間裡,它都將自己標示為 TERM=xterm-ghosttyxterm- 這個前綴是因為有許多不乖的程式會直接對 TERM 做字串比對,來判斷終端機是否支援某些功能。這種做法是錯誤的,而且非常不乖,千萬別這樣做!正確的做法是查詢 terminfo 資料庫

Terminfo 本身就是一個極其有趣(主要是因為它非常棘手難搞)的話題。我希望有朝一日能專門寫一篇關於 terminfo 的文章。這篇開發日誌不會深入探討 terminfo。如果你想一窺這個古老怪獸的面貌,可以在終端機裡執行 infocmp 看看。

過去一個月來,我們一直嘗試擺脫 xterm- 前綴,直接成為 TERM=ghostty。在這個過程中,我們發現了自身 terminfo 資料庫的不少 Bug,也發現了一些上游的問題。我們正一邊進行一邊修復這些問題。

最近,我們被一個 Vim 的 Bug 卡住了。Vim 9.0 支援 Kitty Keyboard Protocol,卻寫死了支援該協定的終端機清單,而沒有正確地去讀取 terminfo 資料庫。這是一個 Bug,令人驚喜的是,一位 Ghostty 社群成員已經提交了修正這個問題的 pull request。這個問題不會影響 Neovim。

Vim 可是有一點點重要1,所以在這個 Bug 被修復、並且下游發行版廣泛更新之前,我們只好無奈地退回使用 TERM=xterm-ghostty。儘管如此,我仍為我們已取得的進展感到驕傲,也樂觀地相信我們很快就能擺脫 xterm 的枷鎖。

我們還發現了其他上游的 Bug,而讓我感到驕傲的是,Ghostty 社群不僅回報問題,還主動提供了修正。Tim 提交了一個 PR 到熱門的 Go 函式庫 tcell,修復了一個特別嚴重的問題。這是一個很重要的函式庫,因為許多熱門的 TUI 應用程式如 lazygitlazydocker 等都使用了它。沒有這個修正,這些程式除非你明確以 TERM=xterm-256color 執行,否則都會吐出一堆亂碼。希望這個修正能盡快被接受!

這些 Bug 和修正都不是 Ghostty 獨有的,全部都有助於讓程式在面對各種不熟悉的終端模擬器時變得更加穩健。

這項工作主要是由 Tim Culverhouse 所推動,我由衷感謝他在此所做的一切。


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> 是經過 hex 編碼的字串。在上面的範例中,我們將「Smulx」做了 hex 編碼。而回應則包含該 terminfo 條目的 key 與 value,同樣也是 hex 編碼。

我們實作中一個特別酷的地方是,我們利用了 Zig 的 comptime 能力,在編譯時期就產生所有可能的請求與回應。這是從與產生實際 terminfo 檔案相同的來源檔案所產生的,因此我們的 terminfo 和 XTGETTCAP 永遠保持完全同步。

XTGETTCAP 的效能其實根本無關緊要,但我們的 XTGETTCAP 實作卻快得離譜,因為它是經過編譯時期最佳化的查詢表。我們不需要做任何記憶體配置、字串格式化等操作。只要做一次簡單的查詢,找到穩定的字元指標,然後直接寫入 pty 就好。非常酷。

可以看看產生這些內容的 Zig 程式碼片段。我超愛 Zig 的 comptime。


可變字型 (#345)

大多數字型會提供一組固定的樣式,例如「Bold」、「Heavy」、「Medium」、「Italic」等。可變字型則提供了單一的字型外觀,讓 weight、slant 等各種軸向可以在某個範圍內用連續的數值來調整。Ghostty 現在已支援可變字型,以及對 variation 軸向的設定。

首先,來看看可變字型實際是什麼樣子。Inconsolata 有提供可變字型版本,在下方的影片中你可以看到我能精細地控制字元的寬度與粗細。

以下是 Ghostty 使用 Inconsolata 時的預設樣子,未設定任何字型 variation 軸向:

而以下是稍微調整 weight 後的設定。差異很細微,但還是看得出來。先是設定檔內容,接著是截圖。

font-family = Inconsolata
font-variation-bold = wght=500

為什麼上面用的是 wght 而不是 weight?Variation 的 key 是由字型本身決定的,而且字型 variation 必須是四個字元。這些並沒有標準化,所以我們無法安全地把 weight 轉換成 wght。Ghostty 的設定使用字面上的 variation key,使用者可以使用任何字型檢視程式(例如 FontDrop)來確認可用的 key。

在終端模擬器中,對可變字型的支援相對少見,所以我很驕傲我們支援了這項功能(而且是跨平台的!)。這類功能真的能讓你將終端機微調到完全符合你想要的樣子,讓它用起來恰到好處。


結語

再次感謝我們最新一批的 Beta 測試者。每一輪總會帶來一些非常厲害的人,他們在某些領域有著深厚的專業知識,或是用全新、獨特的方式操練終端機來找出問題。

如果你想掌握最新消息,請在 Twitter 或 Mastodon 上追蹤我(連結在頁尾)。這個部落格也有提供 RSS 訂閱

Boo. 👻

註腳

  1. Bram Moolenaar 安息,感謝你為我們付出的一切。

本文章由 muse-spark-1.2-contributor 進行翻譯

留言