VimScriptざっくりチュートリアル(関数編)
関数宣言
:function Func(flg) " グローバルスコープの場合、関数名はアルファベットの大文字で始まる : if a:flg " 引数の参照は、a:引数名 : echo "true" : else : return "false" |" 戻り値を返したい場合、return コマンドを使う : endif :endfunction
関数の呼び出し
:call Func(0) " call コマンドは、渡された関数を実行するコマンド。この場合、false が返る :let test = Func(1) " 戻り値を変数に格納したい場合 :echo Func(1) " 戻り値をそのまま echo したい場合
関数の再定義
.vimrc に関数を定義した後で、:source .vimrc とかして、一度定義した関数が再定義されるとエラーになる
function! で、関数の再定義ができるので、.vimrc に関数を書く場合は、何度も呼ばれることを想定して function! で関数を定義したほうが良い
:function! Func(flg) ... :endfunction
FuncRef
関数ポインタ的な感じに関数への参照を変数に格納できる
:let FuncRef = function('Func') " グローバルスコープの場合、FuncRef 変数も大文字で始まる必要がある :call FuncRef(0)
例外処理
VimScriptは、エラーが発生しても処理を止めない
なので、エラーが発生した時、処理を飛ばしたい場合は、try, catch 構文を使うか、abort 識別が必要
:function! ExceptionTest() : call aaaa() " 未定義の関数 : return "???" :endfunction : :echo ExceptionTest() |" エラーメッセージの後に、"???" が表示される
try, catch 構文
:function! TryCatchTest() : try : call aaaa() " 未定義の関数 : return "???" : catch : " 例外処理 : finally : return "finally" : endtry :endfunction : :echo TryCatchTest() |" "finally" が表示される
abort 識別
関数宣言に abort 識別を付けることで、エラーが発生した時に、即時に関数を抜けるようにできる
:function! AboutTest() abort : call aaaa() " 未定義の関数 : return "???" :endfunction : :echo AboutTest() |" エラーメッセージが表示されて、-1 が返る
関数の範囲指定呼び出しについて
VimScriptでは行を加工する関数、コマンドは、範囲指定をして呼び出すことが出来る
範囲指定をした場合は、範囲の行を1行ずつカレントとして関数が呼び出される
例えばこんなテキストがあった場合
1 2 3 4 5
こんな関数を用意する
:function! Increment() |" カレント行を数値と見なして、+1 する関数 : let line = str2nr(getline('.'), 10) |" カレント行の取得(後述) : let line += 1 : call setline('.', printf("%d", line)) |" カレント行の更新(後述) :endfunction
で、以下のコマンドを実行する
:%call Increment() " 1行目〜最後行に対して、Increment を実行
すると、各行に対して、Increment が実行されて、以下のようになる
2 3 4 5 6
行指定子
行や範囲を指定する場合、以下の文字が使える
- 数値 : 1から始まる行番号(0の場合大抵のコマンドは行頭と解釈する)
- . : カレント行
- $ : 行末
- % : 行頭〜行末
例
:" delete は指定した行 or 範囲を削除するコマンド :3delete " 3行目を削除 :4,10delete " 4〜10行目を削除 :.,$delete " カレント行〜行末まで削除 :%delete " 全部削除
関数の range 識別について
range 識別をつけることで、範囲指定されることを前提とした関数を用意することができる
:function! Increment2() range : for n in range(a:firstline, a:lastline) " a:firstline, a:lastline に範囲指定時の行番号が格納される : let line = str2nr(getline(n), 10) : let line += 1 : call setline(n, printf("%d", line)) : endfor :endfunction
上の例の場合、挙動は Increment とおんなじだけど、関数呼び出しが1回になるので、速度面や、特定の行を保持して、他の行に何かしたい時とかに便利