Vim Variable Variables

上一篇文章介紹 Syntastic 的最後面,其實本來想順便介紹一個 Vim Plugin 設定的 pattern,後來想一想還是獨立一篇文章好了,剛好今年 COSCUP 要介紹一些 Vim 的東西,這篇文章也可以作些 Vim 的介紹,就先從上一篇文章最後面的那行 Vim 設定開始看起:

let g:syntastic_coffee_coffeelint_args = "--csv -f ~/coffeelint-config.json"

在這行設定中,作的事情其實只是宣告並給一個變數值,而我想說的重點是這個變數的變數名稱:g:syntastic_coffee_coffeelint_args,這個變數其實是根據 Syntastic 的文件 5.2 節設定的,其實這個變數名稱裡面有 coffeecoffeelintargs 三個變數,在文件中是這樣描述這個變數的組成的:

syntastic_[filetype]_[subchecker]_[option-name]

表示的是 coffee 這種檔案格式下面,用 coffeelint 時的 args 參數,這種階層式的設定,在其他程式語言通常會用 dictionary 這種資料型態比較多,可是在 Vim 的圈子卻不是這樣,而是比較多用上面這種 Variable Variables 的形式,我想可能原因是: Vim Script 要建立多階層的空 dictionary 不是很方便,要一層一層的建立,而這個問題不管是開發者自己不方便,使用者在 vimrc 裡面作設定也會變得很麻煩。

那在 Vim Script 裡面,要怎樣實作這樣 variable variables 形式的程式呢?很簡單,和 PHP 很像,都是用大括號,所以要讀取最上面那個使用者設定的值很簡單:

g:syntastic_{filetype}_{subchecker}_{optionName}

這樣就好了,真的那麼簡單就好了...

Vim Script 和現在主流的 Scripting 語言差異蠻大的,有很多不太方便的設計,像是設定 list, dictionary 時如果要在不同行寫不同項目的內容,每行間都要加一個反斜線\,資料的型別是強型別,字串和數字都要自己手動作轉換,宣告和改變數的值都要用let等等,而這邊會遇到的限制是,無法存取任何一個不存在的變數,要是有存取到的話都會出現錯誤,即使只有讀取值也是,並不會直接給你 false value 或是像 JavaScript 那樣有undefined,所以要是使用者沒設定過這個變數g:syntastic_coffee_coffeelint_args,我在 Plugin 裡面就不能直接讀取他,不然只會看到紅色的錯誤訊息。

要處理這個問題,要用的是 exists 這個內建的 function,這個 function 是專門用來檢查變數是否存在用的,如果變數存在才做事情,寫起來就像是:

if exists('g:syntastic_' . filetype . '_' . subchecker . '_' . optionName)
    let args = g:syntastic_{filetype}_{subchecker}_{optionName}

實在是不太好看,不過寫 Vim Script 基本上就是常常要寫這樣難看的程式碼,做的都是一些土法煉鋼的事情,其實還蠻辛苦的,而且你現在應該可以想像,如果要用多階層的 dictionary 在 vimrc 裡面作設定會長什麼樣子了。