JavaScript on vim

因為現在主要都是在寫 javascript 為主,所以這兩天調整 Vim 主要目標都是為了 javascript,這篇整理一下使用的 plugin 和相關設定,不過在開始前,請先把 Vim 升級到 7.2,套件沒有的話自己編譯也可以。

syntax/indent

Vim 雖然有內建支援 javascript 的縮排和語法標籤,不過另外都有人維護比較完整的版本,而且不只一種,我沒詳細比較,只是挑看起來比較有在維護的:

照說明把檔案放到正確的位置即可,另外雖然有 jQuery 的 syntax ,不過我安裝後發現會和 The NERD Commenter 衝突,而且看一下內容覺得也沒做的很好,就沒用了。縮排的部份也有人是用外部程式來處理,詳細可以 vim-taiwan 上的 討論 ,我目前是還沒覺得有需求。

自動完成

這部份就比較麻煩了,在自動完成我使用了 snipMate以前snippetsEmu ,不過都沒更新了,而且內建的 snippets 少很多),還有 autocomplpop ,兩者安裝都很簡單,就解到 .vim 目錄下,或是用 c9s 大大寫的 Vimana ,snipMate 別忘了先 hack 一下 讓它支援 autocomplpop ,autocomplpop 雖然新版已經有幫不少檔案格式設定好預設的行為了,包括 html 和 css,但是卻不包含 javascript,所以還要自己設定一下,在 vimrc 裡面加上以下的設定:

let g:acp_enableAtStartup = 1
let g:acp_completeOption = '.,w,b,u,t,i,k'
let g:acp_behaviorSnipmateLength = 1
let g:acp_behaviorKeywordCommand = "\<C-n>"

let jsbehavs = { 'javascript': [] }
    call add(jsbehavs.javascript, {
        \   'command'      : "\<C-x>\<C-u>",
        \   'completefunc' : 'acp#completeSnipmate',
        \   'meets'        : 'acp#meetsForSnipmate',
        \   'onPopupClose' : 'acp#onPopupCloseSnipmate',
        \   'repeat'       : 0,
    \})
    call add(jsbehavs.javascript, {
        \   'command' : g:acp_behaviorKeywordCommand,
        \   'meets'   : 'acp#meetsForKeyword',
        \   'repeat'  : 0,
        \ })
    call add(jsbehavs.javascript, {
        \    'command'  : "\<C-x>\<C-o>",
        \    'meets'   : 'acp#meetsForKeyword',
        \    'repeat'   : 0,
    \})

let g:acp_behavior = {}
call extend(g:acp_behavior, jsbehavs, 'keep')

這樣編輯 javascript 時應該就會做正確的跑出自動完成的候選選項,包括 snipMate、關鍵字自動完成、和 omni 自動完成(好像有翻成全補完的),順便提一下,Vim 7.2 大部分檔案格式不用去設定 omnifunc ,幾乎都會指到自己的預設函式,不過 html 卻沒有,還要自己加下面這行到 vimrc :

autocmd FileType html set omnifunc=htmlcomplete#CompleteTags

而且最好依照我 上一篇的建議 修改一下。

code 檢查

再來是設定讓 jslint 檢查 javascript 程式碼,用的是 jslint.vim ,要記得先安裝 spidermonkey ,然後照說明把檔案移動到 ~/.vim 裡面,這樣就可以執行 :JSLint 來檢查程式碼了,不過一開始一定會發現它對所有的全域變數都發出錯誤訊息,這時可以加上一些設定參數放到 ~/.jslintrc ,我的設定檔內容(其實就是 jslint.vim 提供的範例):

/*jslint browser: true*/
/*global jQuery $ */

第一行是說這些 code 是網路用的,用瀏覽器來執行,所以在這種環境下會出現的全域變數就不會被當成錯誤,第二行則是你自己定義會使用到的全域變數,這個範例是加上了 jQuery 的兩個全域變數,這些設定也可以加在 js 檔案裡面,其他的設定參數請看 官方說明 。不過每次都要執行 :JSLint 也是蠻麻煩的,所以可以設一下快速鍵,另外也可以設定存檔時自動檢查:

map <F12> :JSLintLight<CR>
map <F11> :JSLint<CR>

autocmd FileWritePost,BufWritePost *.js :JSLint

壓縮

最後就是壓縮了, 以前有寫過個 function ,因應 closure-compiler 的出現和建議,現在有作些修改:

function Yuic ()
    let cwd = expand('<afile>:p:h')
    let nam = expand('<afile>:t:r')
    let ext = expand('<afile>:e')
    if -1 == match(nam, "[\._]src$")
        let minfname = nam.".min.".ext
    else
        let minfname = substitute(nam, "[\._]src$", "", "g").".".ext
    endif
    if filewritable(cwd.'/'.minfname)
        if ext == 'js' && executable('closure-compiler')
            cal system( 'closure-compiler --js '.cwd.'/'.nam.'.'.ext.' > '.cwd.'/'.minfname.' &')
        elseif executable('yuicompressor')
            cal system( 'yuicompressor '.cwd.'/'.nam.'.'.ext.' > '.cwd.'/'.minfname.' &')
        endif
    endif
endfunction

autocmd FileWritePost,BufWritePost *.js :call Yuic()
autocmd FileWritePost,BufWritePost *.css :call Yuic()

至於怎麼裝 yuicompressorclosure-compiler 就因系統而異了。

其他

其他還有兩個不是針對 javascript 的 plugin ,不過寫程式時蠻有用的,分別是 The NERD CommenterAlign ,The NERD Commenter 是快速註解用,Align 則是對齊用,例如一連串的變數初值指定,可以用 :Align = 來把等號左右兩邊的程式碼對齊,美觀不少。