2012年2月25日土曜日

[vim] phpファイルを保存するとき、エラーチェックして、エラーがあったらステータスラインを赤にする設定

やったこと


最近、ステータスラインに今カーソルがどの関数にいるかを表示する方法とか、
PHPのエラーチェックやる方法とかを、会社の先輩に教えてもらった。
せっかくなので、ステータスラインの整理をした。
なかなかうまくいった。
特に、保存した時PHPにエラーがあったら、ステータスラインにエラーの内容表示するところとか。

できたもの


ステータスラインのフォーマットは
「ノーマルモード時」、「インサートモード」「PHPエラー検出時」の3パターン。

① ノーマルモード
「背景色を青」、「文字色を白」に変更する。
表示する内容は、「ファイルの絶対パス」、「現在カーソルがいる関数名」、「行数」。


② インサートモード
表示する内容は、インサートモードと同じ。
「背景色を黄色」、「文字色を黒」に変更する。



③ PHPエラー検出時(ファイルタイプがphpのときのみ)
一番やりたかったのはこれ。
ファイルを保存した時、php -lを実行して、
エラーがあった場合、「背景色を赤」、「文字色を黄色」、
「エラーの内容をステータスラインに表示」する。
エラーがない場合は、ノーマルモードと同じ。



設定


.vimrcに設定した内容は以下の通り。

"----------------------------------------------------------+
"  ステータスライン                                        |
"----------------------------------------------------------+

" ステータスラインを常に表示,色変更
set laststatus=2
hi StatusLine ctermfg=White ctermbg=Blue cterm=none
au InsertEnter * hi StatusLine ctermfg=Black ctermbg=yellow cterm=none
au InsertLeave * hi StatusLine ctermfg=White ctermbg=Blue cterm=none
set statusline=%F:\ \ %{GetFunc()}%=%l/%L%11p%%

autocmd BufEnter,BufWritePost * call ErrorCheckStatusline()

" function行の取得用の関数
function! GetFunc()
    let s:path = expand('%:p')
    let s:ext  = expand('%:e')
    if s:ext == "php"
        let start = search("function",'bn')
    elseif &filetype == "vim"
        let start = search("function!",'bn')
    elseif &filetype == "py"
        let start = search("def",'bn')
    else
        let start = ""
    endif

    let lines = getline(start)
    return lines
endfunction

" エラー時のステータスライン変更用関数
function! ErrorCheckStatusline()

  " エラー時の色定義
  let l:ecol = 'highlight StatusLine ctermfg=Yellow ctermbg=Red cterm=none'
  "
  if ! exists('g:is_error')
      " 通常時の色定義
      let s:fg = synIDattr( hlID( "StatusLine" ) , "fg" )
      let s:bg = synIDattr( hlID( "StatusLine" ) , "bg" )
      let g:ncol = 'highlight StatusLine ctermfg='.s:fg.' ctermbg='.s:bg.' cterm=none'
  endif

  " チェックを実行(PHP)
  if &filetype == "php"
    let l:tmp = system("php -l ".bufname(""))

    " エラーがあった場合
    if ! (l:tmp =~ "No syntax errors" )
       let g:is_error = 1
       let g:status = split(l:tmp, '\n')
       silent exec 'set statusline=%{g:status[0]}%=%c,%l%11p%%'
       silent exec l:ecol
       return
    else
       let g:is_error = 0
    endif


  " チェックを実行(python)
  elseif &filetype == "python"
    let l:tmp = system("pyflakes ".bufname(""))

    " エラーがあった場合
    if ! (l:tmp == "" )
       let g:is_error = 1
       let g:status = split(l:tmp, '\n')
       silent exec 'set statusline=%{g:status[0]}%=%c,%l%11p%%'
       silent exec l:ecol
       return
    else
       let g:is_error = 0
    endif

  endif

  " 通常のステータスラインを表示
  silent exec 'set statusline=%F,\ \ %{GetFunc()}%=%l/%L%11p%%'
  silent exec g:ncol
  return
endfunction


今後

① もう少し関数を汎用的にする。
② インサートモードでは、そのモードで必要な情報をステータスラインに表示したい。それが何かは検討中。
③ ビジュアルモードでも何らかの変更をやりたい。
④ vimscript, python のエラーチェックもいれたい。


設定

ここ参考になった。
Vim-Tips
[Vim] statusline

2012年2月20日月曜日

[vim] unite.vimを使って、バージョン管理ツールbazaarをvimから操作する。

bzrをvimから操作するuniteソースを書いた。
探してみると、svnで似たようなことしてる人がいた。
vimスクリプトのuniteでsvn statusとsvn diffするsource書いた
しかし、差分の確認にvimdiffを使いたいという気持ちがあったので、
ゼロから書いてみることにした。

背景


bzrを操作するとき、ほぼ決まりきったコマンドの流れがある。
特に、他の人の変更を確認するとき。

① bzr log --line --forward
② bzr diff -c [リビジョン番号]
③ bzr diff -c [リビジョン番号] [ファイル名]
④ vi [ファイル名]

他の人のコミットした内容を確認したいとき、
まず、bzr logでリビジョン番号を特定し、
bzr diffで変更されたファイルや、その変更内容を確認する。
そのあと、viで開いたりする。

これらの操作をするとき、
一回一回コマンドたたくのは慣れれば特に何も感じないけど、
この流れに沿った操作ができるインターフェースがあれば、
もっと楽になるんじゃないかと考えた。
で、uniteのソースにしようと思った。

ソース

結構長くなってしまったので、githubに置く。

kokukuma / vim-unite-bzr

以下、インストール方法。
ちなみにこれを使うには、unite.vim, vimprocが必要。
また、このインストールは、pathogen.vimを使ったやり方。

$ cd ~/.vim/bundle
$ git clone git://github.com/kokukuma/vim-unite-bzr.git

これだけ。

使い方


主な使い方は2つ。
過去のコミット内容の確認と現在修正した内容の確認。

① 過去のコミット内容を確認

1, Unite bzr_logを実行すると、bzr logを実行した結果が表示される。

2, リビジョンを選択すると、コミットされたファイル一覧が表示される。

3, ファイルを選択すると、vimdiffが起動し、差分を表示する。


② 現在修正した内容の確認

1, Unite bzr_statusを実行すると、修正されたファイルの一覧が表示される。
2, ファイルを選択すると、vimdiffが起動し、差分を表示する。
雰囲気は①と同じ。

なかなか良い感じに仕上がった気がする。


ToDo

① 複数のリビジョンを選択して、修正箇所を確認できるようにしたい。
② commit、mergeは現状、コマンドラインからやったほうが楽だけど、いずれ統合したい。

2012年2月19日日曜日

[vim] 次のfunctionへジャンプするための設定

 背景


ファイル内の特定のfunctionを探すのは地味に大変。
探すために、functionの一覧を表示したり、これかなってfunctionを読んだりするが、
1つのファイルに大量のfunctionが入っているときはめんどい。

functionの一覧を表示する方法として、フォールディングがよくつかわれるが、
個人的にフォールディングは好きじゃない。
展開するのめんどくさいし、ざっと見たいときとかはfunctionしか見えないことがやだ。

そのため今は、フォールディングの設定を使わず、
unite.vimでそのファイルにあるfunctionの行を抽出している。
[vim] 地味に便利。関数を抽出するunite sourceを作った。

ざっとfunctionを読むときは、何も考えず、j/kで移動してみてた。
しかし、長いfuncitonがいっぱい入っているファイルはきつい。
そこで、function間をジャンプするための設定を思いついた。


設定

といっても、以前やったフォールディングの設定を少し変えて流用してるだけ。
[vim][python] ふははは!読める!読めるぞ!

以下をvimrcに書き込む。
" フォールディングはしない。
set nofoldenable

" 折りたたみレベルを設定する関数
function! PHPFoldSetting(lnum)
    let l:line = getline(a:lnum)    
    if l:line =~ 'function'        
        return '>1'    
    elseif getline(a:lnum + 1) =~ ' \* '        
        return 0    
    elseif getline(a:lnum) =~ ' \* '        
        return 0    
    elseif getline(a:lnum + 1) =~ '^\[\d\{4}-\d\{2}-\d\{2} \d\{2}:\d\{2}\]'        
        return 0    
    else        
        return '='
    endif
endfunction

" PHPファイルの場合に設定 
autocmd BufEnter *.php set foldmethod=expr foldexpr=PHPFoldSetting(v:lnum)

" キーバインド
noremap J zj
noremap K zk


こうしておけば、通常ファイルを開いた場合フォールディングはされず、
shift + j / shift + k で、function間をジャンプすることができる。