fudist

vimのカスタマイズとTips

バッドノウハウ、あるいはフォースの暗黒面

これは何?

ここのカスタマイズに関する記事は主に某社での新人さんとのやりとりから生まれた物で、必ずしも有用かどうかはわかりませんが、一部でも役に立つことが有れば幸いです。
基本的にIME関係以外はWindowsでもLinux(Ubuntu)でも共通で使えます。


読みにくいという話もあるので、若干加筆して順次以下のページでも読めるようにしています。
http://d.hatena.ne.jp/fuenor/archive?word=[vim]+[tips]

困ったときは


Windowsのネットワーク共有で読み込みが遅くなる

ネットワーク共有しているファイルの編集が遅い

<目次へ>


長い行が表示されない

vimは長い行があると、画面に収まらない時には表示されません。
表示させたい場合は.vimrcに以下を追加して下さい。
"画面最後の行をできる限り表示する。
set display=lastline

<目次へ>

他のWindowsエディタから移行する人のために


行の移動を表示行で移動したい

デフォルトはこれで便利なこともあるのですが、特に日本語の場合は長くて折り返しされていると非常に面倒なことになります。
キーボードマクロには論理行移動でないと困る場合が多いので<C-p>,<C-n>を使いましょう。
以下を.vimrcに追加してください。
"カーソルを表示行で移動する。論理行移動は<C-n>,<C-p>
nnoremap j gj
nnoremap k gk
nnoremap <Down> gj
nnoremap <Up>   gk

<目次へ>


w,bコマンドが行末で止まらない

vim/gvimの単語単位移動は行末で停止しません。
他のエディタではほとんど見られないのでちょっと慣れるまで違和感があるかもしれませんが、vimとしては通常 Aコマンドを使用するので、こちらの方が合理的ではあります。
慣れない方のために、一応スクリプトを書きました。
移動コマンドw,b,W,E,Bのカスタマイズ

<目次へ>


スペースキーは一画面移動にしてみる試み

さらにShift+Spaceで一画面逆スクロールみたいにするとまるでブラウザみたいです。
これはブラウザを立ち上げてテキストファイルを読んで、必要になったら挿入モードに移行する様なイメージで、意外とvimに慣れるためのいいステップかもしれないと思います。
早い話がvimはテキストエディタではなく、テキスト用ブラウザなのだと考えるとしっくりくるかもしれません。
これは個人的にはvimを使う大きな理由になっています。
だってスクロールするのにスペースキーだけですむのって楽だと思いませんか。

とりあえずスペースキーは押しやすいのは間違いないのでよく考えて好きな機能に割り当てましょう。
私は<Space>,<S-Space>で一画面単位スクロール、g<Space>でファイルの最終行へ、Alt+<Space>で空白挿入にしています。
g<Space>だけmapなのはGがモーション(移動指定)だからです。
nnoremap <SPACE>   <PageDown>
nnoremap <S-SPACE> <PageUp>
map      g<SPACE>  G
nnoremap <M-SPACE> i<SPACE><ESC><Right>

vnoremap <SPACE>   <C-d>
vnoremap <S-SPACE> <C-u>

<目次へ>


その他の雑多な設定

"ヘルプ
nnoremap <F1> K
"現在開いているvimスクリプトファイルを実行。
nnoremap <F8> :source %<CR>
"強制全保存終了を無効化。
nnoremap ZZ <Nop>
"検索後画面の中心に。
nmap n nzz
nmap N Nzz
  • ヘルプはF1などに割り当ててKはなにか有用なことにリマップして使いましょう
  • .vimrcを書き換えた時<F8>を押すと終了→立ち上げしなくても設定が反映されます。
  •  ノーマルモードでZZは単純に危険なので慣れないうちは無効にしておいた方がよいのではないかと思います。
    これは取り返しの付かない(アンドゥ出来ない)結果になるコマンドだからです。
    ノーマルモードにいることに気がつかず、ZZガンダムが……と書こうとしただけで他のファイルまで全て上書き保存して終了されたら結構ダメージ大きくないですか?

<目次へ>


ノーマルモード


現在のファイル名を無名レジスタにコピー

if has('win32')
  nnoremap <silent> gkf :let @*=expand('%:p')<CR>:echo "Copy filename to noname register."<CR>
elseif has('unix')
  nnoremap <silent> gkf :let @"=expand('%:p')<CR>:echo "Copy filename to noname register."<CR>
endif

もしくは挿入モードで<C-r>=に続けて好きな関数を実行して貼り付け可能なのでそちらでも良いかもしれません。
i<C-r>=expand('%:p')<CR>


最後に編集したコマンドをもう一度実行

これはかなり重要と思います。

. で編集を繰り返すのはよく知られている思います。
同様に & で最後のsコマンドを繰り返せます。
他にもたとえばgvはビジュアルモードで最後に選択した範囲を再選択してくれます。
oで選択範囲の先頭と後尾に移動します。

vimにはたくさんの"最後の編集位置"への移動コマンドがあります。
gi `` '' `. 等々覚えきれないぐらい有ります。
map gb `.zz
nnoremap <C-g> g;
nnoremap g; g,
個人的には
gb    : 最後の編集位置へ移動
<C-g> : 編集位置をさかのぼる
で落ち着きました。

最後に編集したバッファへ切り替えたい事もよくあると思います。
:b#で切替もいいのですが、<C-^>でも切り替えられます。
"window分割していないとき、<C-w><C-w>で裏バッファへ切り替え。
nnoremap <silent> <C-w><C-w> :<C-u>call MyWincmdW()<CR>
nnoremap <silent> <C-w>w :<C-u>call MyWincmdW()<CR>
function! MyWincmdW()
  let pn = winnr()
    silent! wincmd w
  if pn == winnr()
    silent! b#
  endif
endfunction


<目次へ>


カーソル位置の単語とヤンクした単語を置換

個人的によくやるのがこれです。

ciyはテキストオブジェクト的にカーソルが単語内の何処にあっても使えます。
cyはカーソル位置以降の文字列とヤンクした単語を置換します。
一度cyやciyを実行した後、n.で繰り返せる用に、検索レジスタが置換された文字列と置き換わります。
nnoremap <silent> ciy ciw<C-r>0<ESC>:let@/=@1<CR>:noh<CR>
nnoremap <silent> cy   ce<C-r>0<ESC>:let@/=@1<CR>:noh<CR>
同様にヤンクした文字を貼り付けます。
nnoremap gy "0P
この場合はカーソル位置の前に挿入したいことが多いので、Pで貼り付けています。
単純にpだとレジスタの内容が入れ替わっていることも多いのでヤンクレジスタを指定して貼り付けます。

<目次へ>


ヒストリ貼り付け

:di でレジスタの状態を見てみます。
"0 はヤンクした文字列専用のレジスタ
"1 - "9 は削除した文字列が削除順に並んでいます。
9個削除レジスタがあるのは意味があります。
何回か適当な行を削除してみてから
"1P.....
とノーマルモードで入力してみてください。
ヒストリ順に貼り付けになっているのがわかると思います。
"1P.u.u.u
などとやると、削除文字列を選んで貼り付けることが出来ます。
もちろん"3Pみたいに番号を直接指定して貼り付けも出来ます。
コピーしたい行が分散している時、それぞれの場所で削除→アンドゥを繰り返してから実行してやると便利です。

<目次へ>


ヒストリ貼り付け2

前回のヒストリ貼り付けですが削除文字列しか対応していません。
dduで削除→アンドゥを繰り返してから貼り付けするのもいいのですが、コピーしたいところを何カ所かヤンクして貼り付けできると便利だと思いませんか。
次のスクリプトはヤンクした行を削除レジスタにコピーする物です。
nmap <silent> Y   Y:CpR0toR1<CR>
vmap <silent> Y   Y:CpR0toR1<CR>
vmap <silent> y   y:CpR0toR1<CR>
omap <silent> y   y:CpR0toR1<CR>
"行単位のみ
command! CpR0toR1 if @0 =~ "\<NL>"|let @9=@8|let @8=@7|let @7=@6|let @6=@5|let @5=@4|let @4=@3|let @3=@2|let @2=@1|let @1=@0|endif
これでヤンクした行も削除レジスタに入るようになり、
"1P.....
でヤンクした行でもヒストリ貼り付けができるようになります。

ヒストリ貼り付けを多用したり、単語単位でヤンクした物まで反映して欲しいなら、"yankring.vim"のようなスクリプトを使用する方がいいかもしれません。
http://www.vim.org/scripts/script.php?script_id=1234

<目次へ>


検索レジスタに文字列設定

検索で#を使っていますか?
私は使っていません。
n N で繰り返す時、逆になって面倒くさいからです。

なので * を押した時検索文字列の設定と表示のみを行い、方向は次からn Nで指定するようにしています。
#の場合はカーソル位置から単語の末尾まで検索、g*では非単語単位の検索になるように設定しました。
また文字列選択中には選択した文字を検索文字列に設定するようにしています。
"カーソル位置の単語を単語単位の検索文字列に設定
nnoremap <silent> *  :<C-u>call MySetSearch('""yiw', 'word')<CR>:let &hlsearch=&hlsearch<CR>
"カーソル位置の単語を非単語単位の検索文字列に設定
nnoremap <silent> g* :<C-u>call MySetSearch('""yiw')<CR>:let &hlsearch=&hlsearch<CR>
"カーソル位置から単語の末尾までを検索文字列に設定
nnoremap <silent> #  :<C-u>call MySetSearch('""ye')<CR>:let &hlsearch=&hlsearch<CR>

"文字列選択中なら選択文字列を検索レジスタに設定。
vnoremap <silent> * :<C-u>call MySetSearch('""vgvy')<CR>:let &hlsearch=&hlsearch<CR>
vnoremap <silent> # :<C-u>call MySetSearch('""vgvy')<CR>:let &hlsearch=&hlsearch<CR>

""""""""""""""""""""""""""""""
"検索ワードをセットする。
"何か追加パラメータが設定されていたら、単語単位検索に。
""""""""""""""""""""""""""""""
function! MySetSearch(cmd, ...)
  let saved_reg = @"
  if a:cmd != ''
    silent exec 'normal! '.a:cmd
  endif
  let pattern = escape(@", '\\/.*$^~[]')
  let pattern = substitute(pattern, '\n$', '', '')
  if a:0 > 0
    let pattern = '\<'.pattern.'\>'
  endif
  let @/ = pattern
  let @" = saved_reg
endfunction


<目次へ>



縦に連番を入力する

vim/gvimで縦に連続した番号へ置換したいときがあります。

fuga[0]
fuga[0]
fuga[0]

これを次のように変更したりする場合です。

fuga[0]
fuga[1]
fuga[2]

適当なのが見あたらなかったので、適当に作ってみたものを使用しています。

.vimrc(_vimrc) に追加して使います。

nnoremap <silent> co :ContinuousNumber <C-a><CR>
vnoremap <silent> co :ContinuousNumber <C-a><CR>
command! -count -nargs=1 ContinuousNumber let c = col('.')|for n in range(1, <count>?<count>-line('.'):1)|exec 'normal! j' . n . <q-args>|call cursor('.', c)|endfor

使い方

カーソルを連番に置換したい数値に合わせて 3co と実行すると、縦に3行分が連番に置換されます。
ビジュアルモードで選択してから co だと選択行が連番に変更されます。
<C-a>を使用しているので、連番変更の対象になるのはカーソル位置から最も近い右側の数字です。
必ずしも数値の上でなければいけないという事はありません。
ただし対象範囲は全て同じ数字(開始値)にしておく必要があります。
また puyo1, puyo2, ...のような数値にも有効です。
fuga[2][1]
fuga[2][1]
fuga[2][1]

puyo1
puyo1
puyo1

数値が不揃いの場合は

  1. <C-v>で数値部分を矩形選択
  2. s0 などとして連番の初期値に置換
  3. gvで範囲再選択
  4. co
という感じに、整形してから連番変更すると良いのではないかと思います。
ビジュアルモードでは <C-a> や <C-x> に割り当てるとそれっぽいかもしれません。
vnoremap <silent> <C-a>   :ContinuousNumber <C-a><CR>
vnoremap <silent> <C-x>   :ContinuousNumber <C-x><CR>
<目次へ>


変更されている時のみ保存

変更がないのに保存するとタイムスタンプのみ変更されて、あまりよろしくありません。
:update
なら変更のない時は保存されません。
キーマップに定義も出来ます。
"バッファ変更時のみ保存
nnoremap <silent> <C-s> :<C-u>update<CR>
.gvimrcに以下を付け加えると強制保存と、更新時のみ保存をメニューでも使い分けられます。
silent! aunmenu &File.保存(&S)
amenu <silent> 10.340 &File.保存(&W)<Tab>:w  :if expand('%') == ''<Bar>browse confirm w<Bar>else<Bar>confirm w<Bar>endif<CR>
amenu <silent> 10.341 &File.更新時保存(&S)<Tab>:update  :if expand('%') == ''<Bar>browse confirm w<Bar>else<Bar>confirm update<Bar>endif<CR>

<目次へ>


Diff

:DiffOrig
現バッファと差分表示は便利です。最後に保存してからの編集箇所がわかります。

:Diff #
裏バッファと差分表示もなかなか便利です。
差分を取りたいファイルを開いて、裏バッファになるようにしてから実行します。
Diff 3 の様にバッファ番号指定も出来ます。
"現バッファの差分表示。
command! DiffOrig vert new | set bt=nofile | r # | 0d_ | diffthis | wincmd p | diffthis
"ファイルまたはバッファ番号を指定して差分表示。#なら裏バッファと比較
command! -nargs=? -complete=file Diff if '<args>'=='' | browse vertical diffsplit|else| vertical diffsplit <args>|endif
DiffOrigは公式のvimrcサンプルに書かれています。

<目次へ>



IMEがONの時IMEをOFFにしてfコマンド実行

fコマンドは大変便利ですが、私は基本アルファベットしか検索しません。
なのでfコマンドを実行する時にIMEは自動でOFFにしています
nnoremap <silent> f :set iminsert=0<CR>f
nnoremap <silent> F :set iminsert=0<CR>F

<目次へ>

挿入モード



Emacs風味なキー設定

本来vimの挿入モードは長居をするところではありません。
とはいえ挿入モードだけでほとんどの入力編集を可能にすることも出来ます。
若干Emacs風味なvimのキー設定を書いてみたので参考にしてください。

若干Emacs風味なvimのキー設定

<目次へ>


日本語を使いやすくする

Linux(Ubuntu)でSCIMやuimを制御して、ノーマルモードでのIM自動オフや日本語入力固定モードについては以下のページを参照してください。
http://d.hatena.ne.jp/fuenor/20091004

vim/gvimでは日本語が使いにくいと言われます。
しかし挿入モードのみで扱っている場合さほどの違いが出るわけではありません。
前回の挿入モードのカスタマイズ例でも見たとおり一通りのことは出来なくはありません。
もちろんノーマルモードと頻繁に行き来する場合はIMEの切り替えが面倒くさくなることも確かです。
とくにWindowsのgvimの場合はIMEの制御が可能なので、自分の好みに合わせてカスタマイズしてやるとかなり使いやすくなります。
まずわかりやすくするためにIMEの自動制御を無効にします。
"挿入モード終了時にIME状態を保存しない
inoremap <silent> <ESC> <ESC>
inoremap <silent> <C-[> <ESC>
inoremap <silent> <C-l> <ESC>
"IMEモード固定
inoremap <silent> <C-j> <C-^>
なぜかこのようにマップするとIMEの自動ON/OFFが<ESC>では無効になります。
これでソースコードに日本語でコメントを書くような時には、
  1. 挿入モードに入ってIME ON
  2. コメントを書く
  3. <ESC>で挿入モードを抜ける
  4. 再び挿入モードへ
で自動的にIMEがOFFになります。

次に日本語をがっつり入力したい場合は、
  1. 挿入モードに入って<C-j>でIME ON
  2. なにかを書く
  3. <ESC>で挿入モードを抜ける
  4. 再び挿入モードへ
で今度はIMEが自動制御でONになります。
ノーマルモードで移動してまた日本語を入力したい場合に便利かと思います。

行連結のために次の設定を .vimrc に追加しても良いと思います。
"日本語の行の連結時には空白を入力しない。
set formatoptions+=mM
またW,B,Eですが、これは空白のみを基準に移動するコマンドで、日本語の場合はほとんど使い道がありません。
これが日本語の時だけ "、。" などでも止まるようにすると、長い日本語の行内を移動する時に便利だと思いスクリプトを書きました。
移動コマンドw,b,W,E,Bのカスタマイズ

<目次へ>


IMEの状態でカーソル色を変えたい

gvimではhighlightのCursorIMを設定するとIMEの状態によってカーソル色を変えることができます。
helpでは gvimrcに設定を追加するように、と説明されています。
しかし公開されているカラーファイルで CursorIMを設定しているものはほとんど無く、カラー設定を一度リセットしてからカラー再設定をしているために大抵の場合有効にはなりません。
したがって、.gvimrcでカラーファイルを指定した後にCursorIMを設定するか、カラーファイルにCursorIMを追加してやるのが正解でしょう。
" .gvimrc カラー設定:
colorscheme mycolor

if has('multi_byte_ime')
  highlight Cursor guifg=NONE guibg=Green
  highlight CursorIM guifg=NONE guibg=Purple
endif
新しく増えたハイライトは当然対応していないカラーファイルも多いので
シンタックス(S)→ハイライトテスト(H)
で確認して足りない物は同様に追加してください。
コンソール版のカラー設定は .vimrc、GUI版は .gvimrcで設定しないと有効にならないので、vimfiles(Linuxは.vim)のcolorsに好きなカラーファイルをコピーして 識別名を変更したカラーファイルに直接書き加える方がよいかもしれません。

サンプルカラーファイル
mycolor.vim (公式で配布されているdarkblue.vimに各種ハイライトを追加、変更したもの。colors_name = "mycolor")

darkblue.vimを mycolor.vimにリネームして vimfiles/colors へコピーし、以下を最終行に追加する。
" orignal "darkblue" end

let colors_name = "mycolor"

hi String     ctermfg=brown guifg=Orange cterm=none gui=none
hi MatchParen guifg=Yellow guibg=DarkCyan
hi SignColumn guibg=#101020
hi CursorIM   guifg=NONE guibg=Red
hi CursorLine guifg=NONE guibg=#505050

その他にも、挿入モードに入ったらステータスラインの色を変更すると便利かもしれません。
挿入モード時、ステータスラインの色を変更

<目次へ>



index