Neovim 0.7 剛剛發布,帶來了許多新功能(當然還有大量的錯誤修復)。您可以在這裡找到完整的發行說明,但在這篇文章中,我將僅介紹一些新增功能。
Neovim 0.5 將 Lua 作為 Neovim 生態系統中的一等公民引入:Lua 現在可以用在用戶的初始化檔案、外掛程式、配色方案、ftplugin 等等。基本上,任何你可以使用 .vim
檔案的地方,你現在都可以使用 .lua
來替代。
然而,當時 Lua API 仍然有一些缺點。最明顯的缺點是無法在 Lua 中建立自動命令,以及將按鍵映射直接綁定到 Lua 函數。為了執行這些操作,用戶需要藉助透過 Vimscript 轉換的變通方法,這有點笨拙。
-- Using a Lua function in a key mapping prior to 0.7
local function say_hello()
print("Hello world!")
end
_G.my_say_hello = say_hello
vim.api.nvim_set_keymap("n", "<leader>H", "<Cmd>call v:lua.my_say_hello()<CR>", {noremap = true})
自動命令和自訂使用者命令的情況也類似。
在 Neovim 0.7 中,現在可以直接在 Lua 中使用所有常用的設定基本要素(按鍵映射、自動命令、使用者命令等),而無需進行 Vimscript 轉換。這也使得可以直接將按鍵映射和自動命令綁定到本地 Lua 函數。
-- Using a Lua function in a key mapping in 0.7
vim.api.nvim_set_keymap("n", "<leader>H", "", {
noremap = true,
callback = function()
print("Hello world!")
end,
})
-- Creating an autocommand in 0.7
vim.api.nvim_create_autocmd("BufEnter", {
pattern = "*",
callback = function(args)
print("Entered buffer " .. args.buf .. "!")
end,
desc = "Tell me when I enter a buffer",
})
-- Creating a custom user command in 0.7
vim.api.nvim_create_user_command("SayHello", function(args)
print("Hello " .. args.args)
end, {
nargs = "*",
desc = "Say hi to someone",
})
您可能會注意到 nvim_set_keymap
必須將 Lua 回呼設定為最終表格參數中的鍵,而 nvim_create_user_command
可以將回呼函數直接作為位置參數傳遞。這是 Neovim 嚴格 API 合約的結果,該合約規定在 API 函數進入穩定版本後,其簽名不得以任何方式更改。然而,因為 nvim_create_user_command
是一個新的 API 函數,我們能夠透過使其第二個參數接受字串或函數來增加一些便利性。
Neovim 0.7 還包含一個僅限 Lua 的便利函數 vim.keymap.set
,用於輕鬆建立新的按鍵映射。
vim.keymap.set("n", "<leader>H", function() print("Hello world!") end)
vim.keymap.set
與 nvim_set_keymap
的不同之處在於以下幾點
noremap
,因為這是用戶 99% 的時間都想要的。說明文件包含更多資訊:在 Neovim 中執行 :h vim.keymap.set
以了解更多資訊。
最後,用戶現在可以使用 API 函數 nvim_set_hl
來修改全域高亮組(相當於使用 :hi
),從而開啟純 Lua 配色方案的大門。
作為一個基於終端機的應用程式,Neovim 長期以來一直受到終端機模擬器的限制,其中之一就是許多按鍵的編碼相同,因此在終端機中執行的應用程式無法區分。例如,<Tab>
和 <C-I>
使用相同的表示形式,<CR>
和 <C-M>
也是如此。這長期以來意味著無法單獨映射 <C-I>
和 <Tab>
:映射其中一個必然會映射兩者。
這長期以來一直是一個令人惱火的問題,並且有很多解決方案可以解決它。Neovim 使用 Paul Evans 的 libtermkey,而 libtermkey 又使用 Evans 自己的 fixterms 提案,以明確的方式對修飾鍵進行編碼。只要控制 Neovim 的終端機模擬器以這種方式發送編碼的按鍵,Neovim 就可以正確解釋它們。
Neovim 0.7 現在在其自己的輸入處理中正確地區分這些修飾鍵組合,因此使用者現在可以分別映射例如 <Tab>
和 <C-I>
。此外,Neovim 在啟動時發送一個跳脫序列,向控制終端機模擬器發出訊號,表示它支援這種按鍵編碼樣式。一些終端機模擬器(例如 iTerm2、foot 和 tmux)使用此序列以程式方式啟用不同的編碼。
警告:這是一把雙面刃!您可能會發現現有的 <Tab>
或 <C-I>
(或 <CR>
/<C-M>
)映射不再起作用。但是,修復方法很簡單;只需修改您的映射以使用您想要使用的實際按鍵即可。
除了消除這些修飾鍵對的歧義外,這還啟用了以前不可能實現的新按鍵映射,例如 <C-;>
和 <C-1>
。
對此的支援很大程度上取決於您使用的終端機,因此這不會影響所有使用者。
Neovim 0.7 引入了一個新的「全域」狀態列,可以透過設定 laststatus=3
來啟用。全域狀態列不是每個視窗都有一個狀態列,而是在 Neovim 包含視窗的整個可用寬度上執行。這使得它可以顯示每個視窗不會變化的資訊,例如 VCS 資訊或目前的工作目錄。許多狀態列外掛程式已經在使用此新功能。
在 Neovim 0.7 中,有一種新的(實驗性)方法來進行檔案類型檢測。關於檔案類型檢測的簡要說明:當您第一次啟動 Neovim 時,它會載入 $VIMRUNTIME
目錄中名為 filetype.vim
的檔案。此檔案建立數百個 BufRead,BufNewFile
自動命令,其唯一目的是根據有關檔案的資訊(最常見的是檔案的名稱或副檔名,但有時也使用檔案的內容)推斷檔案的檔案類型。
如果您使用 nvim --startuptime
分析您的啟動時間,您會注意到 filetype.vim
是載入速度最慢的檔案之一。這是因為建立如此多的自動命令成本很高。另一種進行檔案類型檢測的方法是改為建立一個單一的自動命令,該命令為每個新的緩衝區觸發,然後嘗試透過一系列循序步驟來匹配檔案類型。這就是新的 filetype.lua
所做的事情。
除了使用單一自動命令外,filetype.lua
還使用基於表格的查找結構,這意味著在許多情況下,檔案類型檢測會在恆定時間內發生。如果您的 Neovim 是使用 LuaJIT 編譯的(很可能就是這樣),那麼您還可以從此檔案類型匹配中獲得即時編譯的好處。
此功能目前是選擇性加入的,因為它尚未完全匹配 filetype.vim
涵蓋的所有檔案類型,儘管它非常接近(我已經獨家使用它很多個月而沒有任何問題)。有兩種方法可以選擇加入此功能
使用 filetype.lua
,但回退到 filetype.vim
將 let g:do_filetype_lua = 1
新增至您的 init.vim
檔案。這可以防止檔案類型匹配中的任何回歸,並確保檔案類型始終至少與 filetype.vim
一樣好地被檢測到。但是,您將會付出載入 filetype.lua
和 filetype.vim
的啟動時間成本。
僅使用 filetype.lua
,並且完全不載入 filetype.vim
將 let g:do_filetype_lua = 1
和 let g:did_load_filetypes = 0
都新增至您的 init.vim
。這將專門使用 filetype.lua
進行檔案類型匹配,並提供上述所有效能優勢,但存在檔案類型檢測遺漏的(小)風險。
除了效能優勢之外,filetype.lua
還可以輕鬆新增自訂檔案類型。只需建立一個新的檔案 ~/.config/nvim/filetype.lua
,並呼叫 vim.filetype.add
來建立新的匹配規則。例如
vim.filetype.add({
extension = {
foo = "fooscript",
},
filename = {
["Foofile"] = "fooscript",
},
pattern = {
["~/%.config/foo/.*"] = "fooscript",
}
})
vim.filetype.add
採用一個包含 3 個(可選)鍵的表格,對應於「副檔名」、「檔案名稱」和「模式」匹配。每個表格條目的值可以是字串(在這種情況下,它被解釋為檔案類型)或函數。例如,您可能想要覆蓋 Neovim 預設始終將 .h
檔案分類為 C++ 標頭的行為,方法是使用一種啟發式方法,如果標頭檔案包含另一個 C++ 樣式的標頭(即,沒有尾隨 .h
的標頭),則僅將檔案類型設定為 C++。
vim.filetype.add({
extension = {
h = function(path, bufnr)
if vim.fn.search("\\C^#include <[^>.]\\+>$", "nw") ~= 0 then
return "cpp"
end
return "c"
end,
},
})
我們每天都在使 filetype.lua
更接近與 filetype.vim
的完全對等。我們的目標是使其在 Neovim 0.8 中成為預設值(可以選擇退出到傳統的 filetype.vim
)。
Neovim 0.7 將 neovim-remote 的一些功能引入到核心編輯器中。您現在可以使用 nvim --remote
在已執行的 Neovim 實例中開啟檔案。一個例子
# In one shell session
nvim --listen /tmp/nvim.sock
# In another shell session, opens foo.txt in the first Nvim instance
nvim --server /tmp/nvim.sock --remote foo.txt
新遠端功能的一個用例是能夠從主要 Neovim 實例中的嵌入式終端機模擬器開啟檔案,而不是建立一個在 Neovim 本身內部執行的嵌入式 Neovim 實例。
Neovim 是一個由熱衷於此的個體所組成的鬆散結構專案,他們為了樂趣而工作;因此,任何路線圖總帶有猜測的成分。不過,已經有一些正在醞釀中的事情,您可能會在 Neovim 0.8 中看到它們。