Fish,全稱 "the friendly interactive shell", 是一款使用者友好、功能強大的 shell,以其開箱即用的特性和美觀的介面而聞名。2月27日,Fish 迎來了 4.0 版本的重大更新,官宣地址 https://fishshell.com/blog/new-in-40。本次更新不僅帶來了諸多新特性和改進,更是在底層架構上完成了從 C++ 到 Rust 的徹底重寫。
Fish 最初是用 C 編寫的,後來移植到 C++,而這次是從 C++ 到 Rust 的重大轉變。這次重構的意義在於:
-
增強安全性:Rust 語言以其記憶體安全特性而著稱,可以有效避免 C++ 中常見的記憶體洩漏、空指標等問題。
-
提升開發效率:Rust 擁有現代化的工具鏈和友好的錯誤提示,能夠顯著提高開發效率。
-
改善併發性:Rust 在併發程式設計方面具有優勢,為 Fish 未來實現真正的多執行緒執行奠定了基礎。
Fish 4.0 中移除了大約 57,000 行 C++ 程式碼,並新增了大約 75,000 行 Rust 程式碼。這次重寫工作歷時近兩年,涉及 1155 個檔案,超過 20 萬行的增刪程式碼。儘管工作量巨大,但 Fish 4.0 在功能和使用體驗上依然保持了穩定。為什麼 Fish 團隊要這樣大刀闊斧地重寫?
變化的原因
Fish 4.0 的變化並非憑空而來,據 Fish 團隊的介紹,是出於下面的原因:
-
C++ 的侷限性:C++ 在工具鏈、開發體驗和安全性方面存在一些問題,例如 C++ 編譯器的升級困難、標頭檔案管理繁瑣、容易出現記憶體錯誤等。C++ 的工具生態不夠完善,升級編譯器比較麻煩,而且 C++ 本身在開發體驗設計上存在不足,字串處理繁瑣且容易出錯。
-
Rust 的優勢:Rust 在工具鏈、開發體驗和安全性方面具有優勢,例如 Rust 擁有強大的包管理器
cargo
、友好的錯誤提示、記憶體安全保證等。Rust 擁有出色的工具鏈,rustup
可以輕鬆安裝和管理 Rust 環境。Rust 在開發體驗方面也表現出色,例如 Rust 的Option
型別可以顯式地處理空指標情況。 -
併發的需求:Fish 希望在內部命令的執行中實現真正的多執行緒併發,而 C++ 在這方面存在一些難以解決的問題。Rust 的
Send
和Sync
特性可以靜態地強制執行執行緒安全規則,從而更容易實現併發。 -
吸引更多貢獻者:Fish 團隊希望透過使用 Rust 這種更現代、更流行的語言來吸引更多的貢獻者。
-
終端整合的需求:為了更好地與各種終端整合,Fish 需要更靈活地處理鍵盤輸入和輸出。
-
使用者反饋:Fish 4.0 的許多新特性和改進都來自於使用者的反饋和建議。
4.0 版本的功能變化
除了底層程式碼的重構,Fish 4.0 還帶來了許多值得關注的新特性和改進:
改進的鍵盤繫結
-
引入了一種全新的鍵盤繫結語法。使用者可以使用
bind ctrl-right
或bind alt-backspace
這樣更直觀的方式來繫結按鍵,而無需使用bind \e\[1\;5C
這種難以理解的轉義序列。 -
增強了對組合鍵的支援。透過啟用
xterm
的 "modifyOtherKey" 和kitty
鍵盤協議等終端特性,Fish 可以區分ctrl+i
、ctrl+shift+i
和Tab
鍵。
改進的命令列體驗
-
現在可以更好地與終端整合。Fish 使用 OSC 133 序列來標記提示符和命令輸出,從而與終端的 shell 整合指令碼更好地協同工作。
-
修復了長命令列的顯示問題。現在,即使命令列長度超過螢幕寬度,Fish 也能正確滾動顯示。
-
commandline
命令的更改會立即生效。例如,commandline -i foo
會立即將 "foo" 插入到命令列中。 -
ctrl-r
歷史記錄搜尋現在支援 glob 語法。例如,git*HEAD
將搜尋包含 "git" 和 "HEAD" 的歷史記錄條目。
支援自定義命令歷史記錄
允許使用者透過定義
fish_should_add_to_history
函式來控制哪些命令會被新增到歷史記錄中。可自安裝的構建版本
現在可以構建為自安裝的二進位制檔案。這意味著你可以將一個包含所有函式、man 手冊和 webconfig 工具的
fish
可執行檔案複製到任何地方,並在沒有 root 許可權的情況下執行它。指令碼功能的增強
-
string match
命令新增了--max-matches
選項,用於限制匹配次數。 -
set
命令新增了--no-event
選項,用於禁止觸發變數更改事件。
總而言之,Fish 4.0 是一次重大的更新,它不僅在底層架構上進行了重構,還帶來了許多新特性和改進。