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

vimrc基礎文法最速マスター

vim

調子に乗って vimrc を書くのに特化した内容のものを書いてみる。取り上げた内容は完全に独断と偏見です。

関連記事: Vimスクリプト基礎文法最速マスター - 永遠に未完成

この記事では vimrc を書くにあたって知っておくべき概念や機能を解説します。Vim 自体の操作方法に関しては触れません。

基礎

バッファ

バッファは、ファイルを編集するための論理的な領域です。Vim で新しくファイルを開くと、新しいバッファが作成されてそこにファイルの内容が読み込まれます。

ウィンドウ

ウィンドウはバッファを画面に表示するための物理的な領域です。分割することができ、1つの画面に複数のウィンドウを表示できます。

タブページ

タブページを使うことでウィンドウの配置を保持したまま複数の画面を切り替えることができます。
タブ文字と区別するためか、タブページと呼ばれています。

モード

Vim の中でも知っておくべき重要なモードを紹介します。これで全てではありません。後ろの括弧内のローマ字は、一般的に略す際の文字です。

ノーマルモード (n)

起動直後のモードです。テキストの編集を行うモードです。全てのモードの基本であり、他のモードの操作が終わるとこのモードに戻ります。

挿入モード (i)

文字を入力するモードです。ノーマルモードから i や a などで移行します。

コマンドラインモード (c)

コマンドを実行するモードです。ノーマルモードから : で移行します。

ビジュアルモード (v)

領域を選択するモードです。選択タイプでさらに文字単位選択、行単位選択、矩形選択

変数

Vim は変数を持つことができます。Vim は内部の制御でもあちこちで変数を使っていますし、プラグインの挙動の制御には変数を用いる場合がほとんどです。

変数の宣言

宣言に特別な構文はありません。値を代入すればその場で変数が作成されます。

let variable = 0

存在しない変数を使おうとするとエラーになります。

スコープ

Vim の変数は接頭子によってスコープが決定します。

接頭子 スコープ
g: グローバル
b: バッファローカル
w: ウィンドウローカル
t: タブページローカル
s: スクリプトローカル
l: 関数ローカル
v: 組み込み変数

接頭子を省略した場合は、

  1. 組み込み変数に存在した場合は v:
  2. 関数内だった場合は l:
  3. 上記以外ならば g:

とみなされます。
特に v: には注意が必要です。count などの名前は割と使いがちですが、v:count が存在する上この変数は読み込み専用です。

変数の削除

unlet コマンドを使うと変数を未定義の状態にできます。

unlet variable

存在しない変数を削除しようとするとエラーになります。! を付ければこれを回避できます。

unlet! variable  " variable があってもなくてもとにかく削除する
環境変数

$ で始まる変数は環境変数です。通常の文字列変数のように扱えます。
また、普通の変数と違い存在しない環境変数を参照すると空文字列であるように振舞い、エラーになりません。
$PATH などの一部の環境変数Vim も参照します。また、外部コマンドを実行する際にも環境変数は渡されます。

echo $PATH

オプション

Vim には多くのオプションがあり、設定によって Vim の挙動が変わります。
オプションの中にはローカルな値を持てるものがあり、それらのオプションは特定のバッファやウィンドウ内に限定されたオプション値を持つことができます。

オプションの値の種類

オプション値は大きく分けて 3 種類あります。

  • 真偽値 (0 or 1)
  • 数値
  • 文字列

オプションによってどの値が入るか決まっています。

オプションの設定

オプションを設定するには :set コマンドを使います。スペース区切りで複数オプションを同時に設定できます。
スペースはオプションの区切りなので、文字列のオプションにスペースを含めたい場合は \ でエスケープします。

set list listchars=tab:^\ ,trail:_,extends:>,precedes:<

ローカルなオプションを設定する場合は :setlocal コマンドを使います。

setlocal number
変数のように使う

& を接頭子にすることで、Vimスクリプト内でオプションを変数のように扱えます。

echo &number
let &tabstop = 8

オプションのグローバルな値やローカルな値に明示的にアクセスしたい場合は &g: や &l: を使います。

let &l:dictionary = $HOME . '/dict/en.dict'

キーマッピング

キーマッピングは特定のキーシーケンスを別のキーシーケンスに変換する設定です。

map と noremap

キーマッピングには大きく分けて map と noremap の 2 つの種類があります。

  • map はキーシーケンスを展開したあと、さらに別のマップを適用しようとします。
  • noremap は一度だけ展開します。

例えば以下の例は再帰的にマッピングされているため展開時にエラーになります。

" j と gj を入れ替えているつもり
map j gj
map gj j

この場合は noremap を使います。

noremap j gj
noremap gj j

map は予期せぬ再展開が発生する可能性があるので、多くの場合は noremap を使うことになるでしょう。

モードとキーマッピング

キーマッピングの設定はモードごとに独立しています。ノーマルモードで定義したキーマッピングは挿入モードでは適用されません。
モードごとにマッピングを定義するコマンドが分かれており、最初の文字で判別可能です。

コマンド ノーマルモード 挿入モード コマンドラインモード ビジュアルモード
map/noremap - -
nmap/nnoremap - - -
imap/inoremap - - -
cmap/cnoremap - - -
vmap/vnoremap - - -
map!/noremap! - -

※代表的なモードのみを載せたため、この表は不完全です。

キーマッピングのオプション

マップ系コマンドの最初の引数にいくつかオプションを渡すことができます。

<silent>
コマンドラインへの出力を抑制します。キーマッピングからコマンドを実行する場合などに指定します。
<unique>
すでにマッピングが存在する場合、エラーにします。通常は上書きされます。
<buffer>
バッファローカルなキーマッピングを定義します。
<expr>
マップ先の文字列を Vim の式とみなして、評価した結果の文字列をマップ先とします。
特殊なキーについて

スペースや Enter、Control キーとの同時押しなどの特殊なキーは、< と > で囲む記法を使います。

nnoremap <silent> <Space>w :<C-u>update<CR>

スペース + w で保存する設定の例です。<Left> などの方向キーでカーソルの移動も可能です。< という文字自体は、文脈上明確ならばそのまま使えますが、そうでない場合は <lt> を使います。

inoremap <C-p> <lt>p><lt>/p><Left><Left><Left><Left>

スクリプトローカルな関数を呼ぶ場合、関数名の s: の部分に代わりに <SID> を使う必要があります。

function! s:func()
  " ...
endfunction
nnoremap <silent> <C-f> :<C-u>call <SID>func()<CR>
キーマッピングの削除

削除は :unmap 系のコマンドを使います。先頭にモードの文字を付けた :nunmap や :iunmap でモード別のマッピングを削除できます。
また、 :mapclear 系のコマンド (:nmapclear :imapclear 等) で指定モードのキーマッピングを全て削除することができます。
グローバルで定義されているキーマッピングを特定のバッファで無効にしたい場合は、同じキーにマッピングするバッファローカルなキーマッピングを定義します。

nnoremap  j gj
" 特定のバッファでは通常の j を使いたい場合はそのバッファで以下のようにする
nnoremap <buffer> j j

autocommand

Vim には、特定のタイミングで特定のコマンドを実行する autocommand という機能があります。あらかじめ autocommand を定義しておくことで、自動的に処理を実行することができます。

autocommand の定義

:autocmd コマンドを使います。使い方が複雑なので、基本的な使い方のみ示します。

autocmd FileType vim setlocal expandtab shiftwidth=2

FileType はイベントの種類です。カンマ区切りで複数同時に指定できます。
vim の部分はパターンと呼ばれる場所です。パターンに一致する場合のみイベントが実行されます。何に対して一致すればよいかはイベントによります。今回の例ではファイルタイプ名です。パターンを使わないイベントもあるので、その場合は全てにマッチする * を指定します。
最後の部分は実行するコマンドです。複雑なことをしたい場合は関数を定義してそれを呼び出すといいでしょう。
余談ですが、この例では :setlocal を使っています。こうすることでこの設定が他のバッファに適用されないようにしています。

グループについて

autocommand にはグループを指定できます。autocommand をグループに所属させることで、削除や起動などをグループ単位で行うことができます。
グループには「現在のグループ」とも呼べるものがあり、:autocmd で定義する際に明示しなかった場合はその autocommand は現在のグループに属することになります。
現在のグループは :augroup コマンドで変更します。

augroup MyGroup

初期状態ではグループは規定のグループになっています。規定のグループには名前がありません。規定のグループにするには予約された名前である END を使います。

augroup END

グループは変更したら最後には必ず規定のグループに戻す必要があります。

現在のグループを変更せずにグループを指定して autocommand を定義するには、イベント名の前にグループ名を書きます。

autocmd MyGroup FileType vim setlocal expandtab shiftwidth=2
削除する

autocommand を削除するには :autocmd! を使います。引数を付けることで、削除対象を限定できます。

" 現在のグループの autocommand を全て削除する
autocmd!
" MyGroup の autocommand を全て削除する
autocmd! MyGroup
" FileType イベントを全て削除する
autocmd! FileType
" 指定したパターンで定義されたコマンドを全て削除する
autocmd! * pat
" 指定したパターンで定義されたコマンドを全て削除しつつ、新しくコマンドを定義する
autocmd! FileType vim echo 'vim!'
登録時の注意

autocommand は :autocmd コマンドが実行された回数だけ定義されます。同じ Vimスクリプトを何度も読み込み直す場合、autocommand は一旦削除してから再度定義するようにしないと、同じ autocommand がいくつも登録されることになります。

augroup MyGroup
  autocmd!
  autocmd FileType vim setlocal expandtab shiftwidth=2
augroup END

知っておいた方がいい機能

:filetype コマンド

ファイルタイププラグインを有効にするコマンドです。これを使うとファイルタイプごとに固有の設定ができるようになります。
何はなくともこれは有効にしておきましょう。

filetype plugin indent on

ファイルタイププラグインにはインデントプラグインというのもあり、ここではこれも一緒に有効にしています。これで(設定が用意されていれば)現在のファイルタイプにあったインデントが行われるようになります。

:syntax enable コマンド

Vim の構文ハイライト機能を有効にするコマンドです。これを行わないと構文に色が付きません。是非設定しておきましょう。

syntax enable
:source コマンド

外部ファイルを Vimスクリプトとして取り込みます。
環境依存の設定や、vimrc を公開したい場合にパスワードなど公開できない部分を分けるのに使えます。

if filereadable(expand('~/.vimrc.local'))
  source ~/.vimrc.local
endif
has() 関数

Vimコンパイルされた環境やコンパイル時のオプションによって特定の機能を持っていたりいなかったりします。has() 関数は Vim が特定の機能を持っているかどうかをチェックします。これにより 1 つの vimrc で複数の環境に対応できます。

if has('win32')
  " Windows 用の設定
endif

if has('win32unix')
  " Cygwin 用の設定
endif

if has('gui_running')
  " GUI 用の設定
endif
コマンドの結合

autocmd などで 1 つしかコマンドを実行できないが、わざわざ関数を作るのも面倒な場合、| で区切ることで複数のコマンドを実行できます。
ただし、中には区切れないコマンドも存在します。注意してください。区切れないコマンドは :help :bar で確認できます。

autocmd QuickFixCmdPost [^l]* cwindow | redraw!
autocmd QuickFixCmdPost l*    lwindow | redraw!
行継続

Vim スクリプトは、次の行の最初の非空白文字を \ にすることで前の行から継続させることができます。
1 行が長くなりすぎる場合は分割するといいでしょう。
一般的な言語と違い、行末ではないので注意してください。

" これは 1 行
autocmd BufReadPost * if line("'\"") && line("'\"") <= line('$')
                    \ | execute 'normal! g`"' | endif

参考資料

help には有用な情報が多く含まれています。わからないことがあったらまずは help を引きましょう。

オプションの一覧
:help option-list
マップコマンドの一覧
:help :map-commands
autocommand 用のイベントの一覧
:help autocommand-events
has() で調べられる機能の一覧
:help feature-list


最低限の内容にしようとしたので、かなり端折ってます。落とし所が難しかったのですが、もし端折りすぎてわからない部分があったら言ってもらえれば追記するかもです。
以下、関連リンク