Vim script と
vimrc の正しい書き方
2013/9/7 Nagoya.vim
cohama / @c0hama
もくじ
1. Vim script とは?
2. 文法、変数、式
3. 制御構文
4. 関数、コマンド、autocmd
5. vimrc について
6. vimrc の正しい書き方
1. Vim script とは?
さっきの復習
● :から始まるコマンドをExコマンドと呼ぶ
● :write とか :quit とか :split とか
Vim script とは?
● Ex コマンドの : をとって適当なファイルに縦に
並べて書きます
● これが Vim script です
● vimrc は Vim が起動時に自動で実行する Vim
script ファイル
Vim script が何故重要か?
● みんなプラグイン書きましょう
● vimrc は Vim script で書く
● つまり、Vim script を知っているとより凝った設
定を書くことができる
○ Ruby の時はインデント幅 2、JavaScript は 4
○ 保存時に行末スペースをすべて削除
○ 全角スペースを可視化する
○ etc
注意
❖ Vim script は vi からの後方互換性をひたすら
守りながら進化してきた言語です
❖ Vim の進化とともにいろいろな機能が後付けさ
れてきました
❖ という理由があるので言語仕様に文句を言わな
い(あきらめが肝心)
2. 文法、変数、式
Vim script の文法
❖ Vim script は全て Ex コマンド
❖ 大半は Ex コマンド + その引数という構文に
なっている
❖ コマンドの引数がどのように解釈されるかは Ex
コマンドによって異なる
: echo "hello, world"vimrc に書くと
きは : は不要
Ex コマンド 引数
Vim script の例
❖ echo a b
➢ 変数 a と b の内容を出力する
❖ map a b
➢ a というキー入力を b というコマンドに割り当てる
❖ set foldmethod=marker
➢ foldmethod というオプションに文字列 "marker" を設
定する
➢ = の両側にスペースを入れることはできない
❖ let msg = "marker"
➢ msg という変数に文字列 "marker" を設定する
Vim script を書く上で重要なこと
● :help を引く
● どの Ex コマンドがどういう引数をとるかは全て
:help に書いてある
● あと、引数を省略した場合とか ! を付けた場合
とか
変数
❖ let {変数名} = {式}
➢ 例) let name = "cohama"
➢ let x = 1
➢ let x += 1
注意
➢ x += 1 のようには書けません。
➢ これは :x というコマンドに += と 1 という引数を渡すと
いう意味 = Vim が終了する
データ型
❖ 数値
➢ 1 -3 0x2A 0777
❖ 浮動小数点
➢ 1.5 1.0e3
❖ 文字列
➢ "hoge" 'fuga' "u0061"
❖ リスト
➢ [1, 2, "hoge", [0.5, 1.2]]
❖ 辞書(連想配列)
➢ {"xyz": 123, "abc": [1, 2]}
変数のスコープ
❖ トップレベルに書くとグローバル変数になる
❖ 関数の中に書くとローカル変数
❖ その他は明示的に指定する
➢ g:hoge => グローバル
➢ l:fuga => ローカル
➢ s:piyo => スクリプトローカル
➢ a:abcd => 関数の引数
➢ b:xxxx => バッファローカル
➢ w:yyyy => ウィンドウローカル
❖ プラグインの設定でよくグローバル変数を使う
❖ バッファローカルもたまに使う
式
❖ 式が必要とされている場所では、式が使える
❖ 数値計算
➢ 1 + 1.5 a * 2 (3/2 + 1) % 4
❖ 文字列連結
➢ "hoge" . "fuga"
❖ リスト連結
➢ [1, 1, 3] + [4, 5]
❖ 比較
➢ 3 > 2 "hoge" =~# "^ho.*"
❖ 条件演算子
➢ (a == 42) ? "correct" : "wrong"
コメント
❖ Vim script におけるコメントは "
❖ ただし、コメントを書けない場合があるので注意
" これはコメント
let a = 1 " これもコメント
map a b " これはコメントではない!
3. 制御構文
if {condition}
{statement}
endif
if {condition}
{statement1}
elseif {condition}
{statement2}
else
{statement}
endif
条件分岐
if g:is_windows
colorscheme molokai
else
colorscheme desert
endif
例) Windows とそれ以外でカ
ラースキームを変える
ループ
for {var} in {list}
endfor
while {cond}
{statement}
endwhile
for i in range(1, 10)
echo i
endfor
例) 1 から 10 までを出力する
例外
try
{try-block}
catch /{pattern}
{catch-clause}
finally
{finally-clause}
endtry
throw {expr}
Vim script で正しく例外処理を行
うのは結構難しい
4. 関数、command、
autocmd
関数
❖ もちろん Vim script にも関数はある
❖ 組み込み関数
➢ str2nr() : 文字列から数値を返す
➢ sin() : sin 関数
➢ len() : リストまたは辞書の要素数を返す
➢ getpos() : カーソルの位置を返す
➢ rename() : ファイルの名前を変更する
ユーザ定義関数
❖ 自分で関数を作る
" 引数を2倍して返す関数
function! Double(x)
return 2 * a:x
endfunction
" 保存してウィンドウを閉じるユーザ定義関数
function! WriteQuit()
write
quit
endfunction
ユーザ定義コマンド
❖ :コマンドもユーザで定義できる
" 1行目を削除するExコマンド
command! DeleteFirstLine 1delete
" 複雑なことを行うExコマンド
command! DoSomething call DoSomething()
" 引数を取る場合
command! -nargs=* Hoge call Hoge(<f-args>)
autocmd
特定のイベントが発生した際に自動的にコマンドを
実行させる
autocmd [group] {event} {pat} {cmd}
" 保存時に行末スペースを取り除く
autocmd myvimrc BufWritePre * %s/s+$//e
イベント
autocmd に指定できるイベントの例
❖ BufWritePre
➢ バッファ全体が保存される直前
❖ BufWritePost
➢ バッファ全体が保存された後
❖ WinEnter
➢ 別のウィンドウに入った後
❖ WinLeave
➢ ウィンドウから離れる前
❖ FileType
➢ filetype が設定された時
5. vimrc について
vimrc とは
Vim の設定ファイル
Vim を Vim として使うために(ほぼ)必須
vimrc があると Vim は自動的に 'compatible'
オプションをオフにする
(Vim が Vim として動作するようになる)
vimrc の配置
❖ Unix 系の場合
➢ $HOME/.vimrc
➢ $HOME/.vim/vimrc (Vim 7.4 から)
❖ Windows の場合
➢ $HOME/_vimrc
➢ $HOME/vimfiles/vimrc (Vim 7.4 から)
❖ .vim (または vimfiles) で全てを管理するのがおすすめ
❖ ちょっと Vim script を書くだけで、Unix 系と Windows の設
定を共有することも可能 ('runtimepath' を設定)
vimrc には何を書くの?
❖ オプション
❖ マッピング
他には
➢ ユーザ定義コマンド
➢ プラグインの設定
などなど
オプション
❖ Vim の設定といえばオプション
❖ 数えたら 350 くらいありました
" オン(オフ)にする
set number
set nonumber
" バッファローカル
setlocal tabstop=4
setlocal foldmethod=marker
オプション
" デフォルト値に戻す
set runtimepath&
" オンとオフを切り替え
set cusorline!
" オプションを変数のように設定・取得
let &shiftwidth = g:indent
let &tabstop = &shiftwidth
おすすめのオプション
...とかを当てにしない
いろいろ試しながら自分に一番合う設定をさがしま
しょう
:options
:help options
:help option-list
「Vim オプション 一覧」とかで検索して出てくるやつは情報古い
ネットよりも:help
マッピング
あるキーの入力を別のコマンドに認識させる
" <F5> を押すと先頭行に #!/bin/sh と入力
map <F5> ggO#!/bin/sh<ESC>
マッピングの種類
❖ モード別のマッピング
➢ nmap : ノーマルモード
➢ imap : インサートモード
➢ xmap : ビジュアルモード
※ 他にもある
❖ 再マップする、しない
" : と ; を入れ替え
noremap : ;
noremap ; :
※ 再マッピングする意思がなければ基本的には nnoremap
より柔軟なマッピング
<expr> をつけると式の評価結果にマッピングできる
" 下の2つは同じ意味
nnoremap j gj
nnoremap <expr> j "gj"
" 先頭行に変数の値を挿入する
let g:shebang = "#!/bin/sh"
nnoremap <expr> <F5> "ggO".g:shebang."<Esc>"
さっきの
nnoremap <F5> ggO#!/bin/sh<ESC>
6. vimrc の正しい書き方
Vim script には罠がいっぱい
正しい書き方を Tips 形式で紹介します
vimrc を正しく書く
vimrc を一瞬で開く、反映させる
Vim のナイスな設定を思いついたら即座に vimrc
を開いて編集することが重要
nnoremap <F5> :<C-u>edit $MYVIMRC<CR>
gvimrc も必要なら追加
この部分をお好みのコマンドに変えよう
・split (水平分割)
・vsplit (垂直分割)
・tabedit (新規タブ)
などなど
vimrc を一瞬で開く、反映させる
vimrc を編集したら即座に反映させましょう
nnoremap <F6> :<C-u>source $MYVIMRC<CR>
 :source $MYGVIMRC<CR>
※再読み込みすると問題が発生する場合があ
る。これを防ぐにはリローダブルな vimrc を書く
必要がある
リローダブルな vimrc を書く
❖ 詳しくは kana さんの書いた「Vim の極め方」を
参照のこと(http://whileimautomaton.net/2008/08/vimworkshop3-kana-presentation)
" 追加する形のオプションは一旦デフォルト値を設定
set backupdir& backupdir+=hoge
" あるいは起動時しか実行されないようにする
if has('vim_starting')
set runtimepath^=~/.vim
endif
リローダブルな vimrc を書く
" autocmd が複数登録されないように最初に消しておく
augroup myvimrc
autocmd!
augroup END
" 必ず augroup 名を指定して書く
autocmd myvimrc FileType scala setlocal sw=2
グローバルとローカルの設定を区別する
❖ 以下の設定の何が悪い?
" JavaScript のときはインデント幅4
autocmd myvimrc FileType javascript
 set shiftwidth=4 tabstop=4 softtabstop=4
:set はグローバルな設定値も変更してしまう!
代わりに :setlocal を使う
グローバルとローカルの設定を区別する
❖ 正しい設定
" JavaScript のときはインデント幅4
autocmd myvimrc FileType javascript
 setlocal shiftwidth=4 tabstop=4 softtabstop=4
グローバルとローカルの設定を区別する
❖ 以下の設定の何が悪い?
" 行末スペースをハイライトで可視化する
match Error /s+$/
:match はカレントウィンドウにしか作用しない!
(しかも vimrc 読み込み時の最初の1回だけ)
WinEnter イベントを使ってカレントウィンドウが変わる都
度呼ばれるようにする
グローバルとローカルの設定を区別する
❖ 正しい設定
" 行末スペースをハイライトで可視化する
autocmd myautocmd VimEnter,WinEnter *
 match Error /s+$/
マッピングを使い分ける
❖ マッピングを定義するためのコマンドはモードご
とに細かく分かれている
➢ nmap
➢ xmap
➢ imap
➢ cmap
➢ smap
➢ omap
マッピングを使い分ける
❖ 以下の設定で何が起こるか?
" 見た目通りに移動
noremap j gj
noremap k gk
ただの :map はノーマル+ビジュアル+セレクト+演算待ち
モードに作用する
・セレクトモードで j が入力できなくなる
 (neosnippet のようなプラグインで困る)
・dj のようなコマンドの挙動まで変わってしまう
マッピングを使い分ける
❖ こっちのほうが良さげ
" 見た目通りに移動
nnoremap j gj
xnoremap j gj
nnoremap k gk
xnoremap k gk
" omap を残す場合
noremap j gj
sunmap j
noremap k gk
sunmap k
既存のコマンドを潰さないようにする
❖ 以下の設定の何が悪い?
" Ctrl+A で全選択
nnoremap <C-a> ggVG
<C-a> はカーソル下の数値をインクリメントする便利なコ
マンド。
これを潰してしまうなんてもったいない!
既存のコマンドを潰さないようにする
❖ 正しい設定
" g Ctrl+A で全選択
nnoremap g<C-a> ggVG
マッピングする前に :help ^a などで調べること
既存のコマンドを潰さないようにする
❖ 以下の設定の何が悪い?
" <Tab> で現在行をインデント
nnoremap <Tab> >>
Vim では <Tab> と <C-i> が同一視される。
<C-i> は進むコマンドなので潰すのはもったいない!
同一視されるのは他にも <C-m> と <CR> など
既存のコマンドを潰さないようにする
❖ 正しい設定
" <Tab> で現在行をインデント
nnoremap <Tab> >>
" 進むコマンドを退避
nnoremap <C-i> <C-i>
まとめ
Vim script はチューリング完全
Vim script でなんでもできる
vimrc を書いて Vim を自分に最適化
罠に注意
おわり

Vim script と vimrc の正しい書き方@nagoya.vim #1