之前的文章探討了 Fennel、Lisp、函數式編程等概念。從現在開始,我們要開始那些將那些概念應用在 Neovim 的插件開發了。首先,先談一個失敗的學習經驗。
過去,我本來以為開發 Vim 的插件只有 VimScript 與 Lua 兩個選項,發現了 Fennel 之後,就興奮地開始研究。
一開始我發現 Conjure 可以應用 Fennel 的開發,但是,關鍵的跳轉定義不管用。接著,我試著訂出一個看似簡單一點的目標,並且嘗試前進。很快地我發現,遇到問題時,我常常想不出來該怎麼處理。然後,我就把這件事放一邊了。
如果分析一下 Neovim 插件開發需要哪些知識的話,除了 Neovim 編輯器操作的基礎之外,至少還有以下四類型的知識:
我之前犯下的錯誤是:由於身為 Clojure programmer ,本來就持有 Conjure 相關的開發環境知識,我以為自己掌握了這一項之後,就算是掌握了 50% 的知識,所以就直接開始挑戰做專案。然而,實際上,我掌握的必要知識只有 25% 不到。
在知識如此缺乏的前提之下要前進,自然是困難重重。
比較合理的學習策略應該是:
這邊讀者可能會覺得有點疑問,Neovim Runtime 與 API ,有什麼不同嗎?這邊我談的 Runtime 知識主要在以下幾個方面:
這些是必須的知識,而 Neovim API 則包羅萬象,有一些比方說 Tree sitter API 的知識,如果你根本沒有要用到 Tree sitter ,其實也大可以先跳過。
當我們在做一般的網頁應用程式 (Web Application) 開發時,我們通常會先開發軟體,然後單元測試,之後則是搭配資料庫與 Http 伺服器的整合測試。
之前的互動式開發,可以視為相當於單元測試,因為我們可以很快地驗証單一 Fennel 函數的運作。那整合測試的部分呢?我們寫的 Fennel 程式要怎麼與 Neovim 一起運作?
讓 Fennel 程式與 Neovim 一起運作,主要克服兩個挑戰:
runtimepath
,它會利用該變數裡的路徑來尋找 Lua 檔來載入執行。精確一點來講,我們必須將 Lua 程式碼放在 runtimepath
變數所指向的資料夾之下的 /lua
子目錄,我們的程式碼才有可能被 Neovim 找到。為了編譯方便,我們需要再安裝一個插件:nfnl
安裝方式:
~/.config/nvim/init.vim
plug#begin
與 plug#end
夾住的區段,加入 nfnl 的安裝指令call plug#begin(stdpath('data') . '/plugged')
...
" === Fennel (Config) Support ===
Plug 'Olical/nfnl'
...
call plug#end()
:source %
:PlugInstall
fnlfmt
有點衝突,我們必須在 ~/.config/nvim/init.vim
裡,修改 FennelOnSave
的設置。改成下方:augroup FennelOnSave
" Format and compile after save
autocmd!
autocmd BufWritePost *.fnl call Fnlfmt() | NfnlCompileFile
augroup END
在安裝、設置了這個 nfnl 插件之後,如果我們日後在編輯完 $path/fnl/some_file.fnl
並且存檔,該插件就會自動生成一個對應的 $path/lua/some_file.lua
檔。
首先,我們可以用以下的 Neovim Ex 指令,看到 runtimepath
。
set runtimepath?
可以得到:
runtimepath=~/.config/nvim, ...
所以,我們可以得知,Lua 檔放在 ~/.config/nvim/lua
資料夾下,就可以被 Neovim 讀取到。
回顧一下,之前在 day06 時,我們安裝 LuaRocks 時,也是把我們手寫的 luarocks.lua
放在 ~/.config/nvim/lua
資料夾下。
再思考一個很關鍵的問題:「如果被編譯完成的 Lua 檔應該要放在 ~/.config/nvim/lua
資料夾下,那對應的 Fennel 檔呢?」自然是要放在 ~/.config/nvim/fnl
資料夾裡了。
本篇探討 Neovim 插件學習策略,與進行開發插件時的必要 Neovim Runtime 知識。