読者です 読者をやめる 読者になる 読者になる

vimしか使えない

vimを使おう - ウノウラボ
vimerとしては、こういう記事を見つけてしまうと黙っていられないわけです。vimerと言っても、私はhjklがどうしても慣れずに矢印キーを使ってしまう軟弱vimerですが。
そんなわけで、私もちょっとしたvimのtipsを紹介したいと思います。


私が使っているvimのバージョンはvim 7.0なので、vim 6.xでは動かない機能があるかもしれません(特に補完のあたり)。そう言う場合は、vim 7.0をコンパイルして入れましょう。(そのときはvimshellのパッチを是非…vimshellはvim>7.0-0には当たらないので注意)

バックアップファイルの保存先

まずは地味なところから。
vimでファイルを編集すると、そのファイルと同じディレクトリに「~」が末尾に付いたバックアップファイルと、同じように「.swp」が付いたファイルが作られますが、これがなかなか鬱陶しい。かといってバックアップ機能を無効化してしまうとちょっと不安。
そんなわけで、以下の3行を~/.vimrcに書いておくと、バックアップファイルとswpファイルは全部~/.vim-backupというディレクトリに作成されるようになります。

set backup
set backupdir=$HOME/.vim-backup
let &directory = &backupdir

設定したら忘れずに~/.vim-backupディレクトリを作っておいてください。

$ mkdir ~/.vim-backup
$ chmod 700 ~/.vim-backup

検索結果のハイライトをさりげなく消す

検索結果に色を付ける機能は、便利なのですが、検索が終わった後でもずっと色が残るのはいただけない。しかし、~/.vimrcに「set nohlsearch」と書いて、色を付ける機能自体を無効化してしまうのはちょっと惜しい。
そこで、以下のように~/.vimrcに書いておくと、Escを連打したときに色が消えるようになります(もう一度検索するとまた色が付きます)。Escは良く連打しますよね。そんなときにさりげなく色が消えてくれます。このさりげなさが素晴らしい。

set hlsearch
nmap <Esc><Esc> :nohlsearch<CR><Esc>

「:nohlsearch」と、最後にが付いているのがポイントです。これが無いと、Escを1回叩いた後に矢印キーなどを叩いたときにおかしなことになります。


:Explore

vimでディレクトリを開くと、ファイラ(Explore)が起動します。実は使ってみるとこれが結構便利で、「ウィンドウの分割機能」と組み合わせると、非常に良い感じです。以下のコマンドを使うと、「ウィンドウの分割」とExploreの起動を同時に行えます。

:Vexplore!
# ウィンドウを縦に分割して、右側にExploreを起動
# :Ve! でも可

:Hexplore
# ウィンドウを横に分割して、下にExploreを起動
# :He でも可

ただ、だいたいウィンドウを縦や横に分割したいときというのは、もうどうしようもなく分割したいとき(?)で、1回Escでインサートモードから抜けてから:Ve!と叩く(しかもShfitが要る)といのは、もどかしいわけです。
と言うわけで、以下のように~/.vimrcに書いておくと、インサートモードのときでも、Ctrlを押しながらW、Vと押すとウィンドウが縦に分割され、Ctrlを押しながらW、Hと押すと横に分割されます。

" Window
map <C-W><C-V> :Vexplore!<CR>
map <C-W><C-H> :Hexplore<CR>
map! <C-W><C-V> <Esc>:Vexplore!<CR>
map! <C-W><C-H> <Esc>:Hexplore<CR>

ウィンドウの切り替えは、Ctrlを押しながらW、Wで。


ついでに、Exploreで表示されるファイルのソート順(のデフォルト値)は、どうでもいいファイルほど下の方に表示されるようにカスタマイズしておくと良いです。私は以下のように設定しています。

let g:netrw_sort_sequence="[\\/]$,*,\\.\\(mv\\|old\\|cp\\|bak\\|orig\\)[0-9]*[\\/]$,\\.\\(mv\\|old\\|cp\\|bak\\|orig\\)[0-9]*$,\\.o$,\\.info$,\\.swp$,\\.obj$ "

この設定では、

  1. /で終わるファイル名(=ディレクトリ)
  2. その他のファイル
  3. .mvとか.oldとか.old1とかold2とかで終わるディレクトリ
  4. .mvとか.oldとかとかで終わるファイル
  5. .oとか.swpとか.objとか

と言う順番でソートされます。

ウィンドウ分割とExploreを使っていて、やっと:cdコマンドの意味が分かりました。


履歴で補完

同じ文字列を2回入力しないといけないとき、2回目は途中まで打ったら後は補完して欲しい。Ctrl-PまたはCtrl-Nで補完できます。
CやC++のコードを書いているときは、#includeをincludeして補完してくれます。かなり便利です。他にも補完にはctagsと連携した補完などなどあるらしいですが、よく知らないです。便利な使い方をご存じの方、ぜひ教えてください。

補完候補の一覧表示の配色が非常に見にくいので、以下のように設定しておくと良い感じです。

hi Pmenu ctermbg=4
hi PmenuSel ctermbg=1
hi PMenuSbar ctermbg=4

「}」を自動入力

vimRubyを使って拡張できます(./configure時に--enable-rubyinterpオプションが必要)。Lispはサッパリなのですが、Rubyならこっちのもの。

というわけで、「{」を入力したときに「}」を自動的に入力してくれる設定を作ってみました。どうも気味が悪いので私は使っていないのですが…。(作者が使っていないtipsを紹介するのか!)

以下のように~/.vimrcに書いておきます。一気に「{}」とカッコと閉じ括弧を先に入力する派の方でも、「{}}」とはならずに、ちゃんと「{}」になってくれます。それからカッコと閉じ括弧の間にカーソルがあるときに改行を入力したときに、イイ感じにインデントしてくれて幸せです。

function! CompleteNewlineSeparete(pairs)
ruby << EOF
        row = $curwin.cursor[0]
        col = $curwin.cursor[1]
        curline = $curbuf[row]
        curchar  = curline[col]
        nextchar = curline[col + 1]
        pairs = VIM::evaluate("a:pairs")
        pairs.scan(/.{2}/) {|pair|  # 2文字ごと
                if curchar == pair[0] && nextchar == pair[1] then
                        $curbuf[row] = curline[0..(col)]
                        nl = curline[/^[\t\r\n\f\v]*/]
                        nl += String.new( curline[(col+1)..-1] )
                        $curbuf.append(row, nl)
                        break
                end
        }
EOF
endfunction

function! NoDoubleClose(pair)
ruby << EOF
        row = $curwin.cursor[0]
        col = $curwin.cursor[1]
        curline = $curbuf[row]
        prechar  = curline[col - 1]
        nextchar = curline[col + 1]
        pair = VIM::evaluate("a:pair")
        if prechar == pair[0] && nextchar == pair[1] then
                $curbuf[row] = curline[0..(col)] + curline[(col+2)..-1]
                p "ok"
        end
EOF
endfunction

inoremap <Enter> <ESC>:call CompleteNewlineSeparete('{}')<Enter>a<Enter>
inoremap { {}<LEFT>
inoremap } }<ESC>:call NoDoubleClose('{}')<Enter>a

" 「)」も自動入力
"inoremap <Enter> <ESC>:call CompleteNewlineSeparete('(){}')<Enter>a<Enter>
"inoremap ( ()<LEFT>
"inoremap ) )<ESC>:call NoDoubleClose('()')<Enter>a
"inoremap { {}<LEFT>
"inoremap } }<ESC>:call NoDoubleClose('{}')<Enter>a

同じように「)」も自動的に入力させることができますが、うーむ、私は使っていません。