javascript indent in vim
javascriptの自動インデントがしたいんです。
いまいちなのしかなかったので、自作。ソースは下のほうに。
http://d.hatena.ne.jp/nagaton/20070623/1182580881
このプラグイン使ってたんだけどさ、けっこう精度が低い。
foo(hoge,function(){})
の})あたりで誤マッチしたり、いろいろ。
オートインデントの精度が低いと、悲惨なことになるので、なんとかしたい。
このプラグインをベースに改造。ちょっとはマシになったんだけど、ラベルのインデントをどうやればいいのか分からない。
var x= { name: value, func: function() { hogehoge } //ここで二段ぶん戻さないといけない }
みたいなやつ。
マッチする括弧がある行を簡単に取得する方法ってないのだろうか。
これは
var x= { name: value, func: function() { hogehoge } }
という整形にすることで一応解決。
var y={ name: 'hogehoge', value: 10 }
となって、かなりださいけど。
多段にネストした、ブロックがないif/for/else(一般的になんて呼ぶんだろ)のインデントも同じ問題で困った。
if(cond) for(var x in array) if(cond2) hage() foo()
みたいなやつ。これは二段までハードコーディングして、「この形式で三段以上ネストするのは馬鹿か変態」と強弁することにした。
あと、一行ifの判別。
if(cond) body
このif(cond)部にマッチさせるにはどうすればいいのか。
condが複数行になるケースを除外するとしても、正規表現は原理的にネストした括弧のマッチができないはず。
結局、一行ifの行末には*必ず*セミコロンがあるはずだという制限を設けた。
このへん、かなり適当なことしてるからむりしないでね。素直に中括弧書いたほうがいいよ。
というか、正規表現による行単位マッチで自動インデントしようってのが無謀なんだよね。誤認識が許されない(一箇所間違えると連鎖的に後方のインデントが崩れる)んだから。理想的には構文解析ベースじゃないと困る。
BNFベースの文字列検索とかできるといいんだけど。
以下ソース。indent/javascript.vimにいれるとうごくよ
" Vim indent file " Language: JavaScript " Author: id:gnarl(http://d.hatena.ne.jp/gnarl) " URL: - " Last Change: 2007 aug 4 " " oritinal author: Ryan (ryanthe) Fabella <ryanthe at gmail dot com> " original file: http://www.vim.org/scripts/script.php?script_id=1936 if 1 "release only if exists('b:did_indent') finish endif let b:did_indent = 1 " Only define the functions once per Vim session. if exists("*GetJsIndent") finish endif endif setlocal indentexpr=GetJsIndent() setlocal indentkeys=0{,0},0),0:,!^F,o,O,e,*<Return>,=*/ " Clean CR when the file is in Unix format if &fileformat == "unix" silent! %s/\r$//g endif function! GetJsIndent() let pnum = prevnonblank(v:lnum - 1) if pnum == 0 return 0 endif let ppnum=prevnonblank(pnum-1) let pppnum=prevnonblank(ppnum-1) let line = substitute(getline(v:lnum),'//.*','','') let pline = substitute(getline(pnum),'//.*','','') let ppline='' if ppnum != 0 let ppline=substitute(getline(ppnum),'//.*','','') endif let pppline='' if pppnum != 0 let pppline=substitute(getline(pppnum),'//.*','','') endif let ind = indent(pnum) let line_end='\s*$' let js_name='[a-zA-Z_][a-zA-Z0-9_]*' let js_lit='\S*' let reg_or='\|' "normal block if pline =~ '('.line_end .reg_or.'{'.line_end .reg_or.'['.line_end let ind=ind+&sw endif if line =~ '^\s*}'.reg_or.'^\s*)'.reg_or.'^\s*})'.reg_or.'^\s*]' let ind=ind-&sw endif " if/else/for let js_open_oneline='^\s*if(.*)' .line_end .reg_or. '^\s*for(.*)' .line_end .reg_or. '^\s*}\=\s*else'.line_end if pline =~ js_open_oneline let ind=ind+&sw endif if ppline =~ js_open_oneline && pline !~ js_open_oneline let ind=ind-&sw endif if pppline =~ js_open_oneline && ppline =~ js_open_oneline && pline !~ js_open_oneline let ind=ind-&sw endif " object name/case label let obj_name='^\s*'.js_name.'\s*:' let case_label='^\s*case\s*'.js_lit.'\s*:' let label=obj_name.reg_or.case_label if line=~label && pline !~ label let ind=ind-&sw endif if pline =~label && line !~ label let ind=ind+&sw endif return ind endfunction