Vim
AdventCalendar
vimrc
HameeDay 5

作って覚える Vim script

More than 1 year has passed since last update.

はじめに

Vimmerの皆さんこんにちは。
Vimに慣れてくると、色々カスタマイズしたくなりますよね。
でも、プラグインを作るのは大げさだし…と思っている人には
.vimrcでVim Scriptを書いてみるのがおすすめです。

Vim Scriptとは

Vim script は Vim に組み込まれたスクリプト言語です。
vimを開き、 :help vim-script と打ってみましょう。

はじめに

誰もが最初に触れる Vim script は vimrc ファイルです。Vim が起動するときに読
み込まれ、書かれているコマンドが実行されます。それにより好きなように設定を変更
できます。vimrc の中ではすべてのコロンコマンドが使えます (":" で始まるコマンド
のこと。Ex コマンドやコマンドラインコマンドと呼ばれることもある)。

(自分のVimはヘルプが日本語じゃないからやだ!という人はこちらをどうぞ→ Vimヘルプを日本語化!)

「誰もが最初に触れる Vim script は vimrc ファイルです。」ということで
実はVimを触っていれば自然とVim scriptにお世話になっているのです。
シンタックスハイライトに使うカラースキームも、もとを正せばVim script。
Vimが有りさえすれば、そこが実行環境。というわけで気軽に始めてみましょう。

こんな人向け

  • Vimを触っていて、プラグインも使っているけど、もっと痒いところに手が届く自動化をしてみたい人
  • もともと別のプログラム言語を触っているが、Vim scriptは触ったことがない人

今回やってみること

  1. Vim上でPHP lintを実行する
  2. lintでエラーが出た行数をハイライトしてみる
  3. 上記を保存時に実行できるようにする

環境

OS: Mac OS Sierra(10.12.6)
Vim: 8.0

1. Vim上でPHP lintを実行する

これはぶっちゃけいろんな人がやっていますので、
本能の赴くまま、無邪気に作って保存してみましょう。

~/.vimrc
function! PHPLint()
    let result = system('php -l ' . bufname(""))
    echo result
endfunction

→保存・コマンドモードで以下を実行
:source ~/.vimrc

test.php
<?php

$hoge = 1;
aaa // 明らかなシンタックスエラー

echo $hoge;

→保存

コマンドモードで
:call PHPLint() を実行

すると、こんな表示が出ます

スクリーンショット 2017-12-03 16.55.55.png

楽しい\(^o^)/

簡単な解説

関数はfunction ~ endfunctionで定義します。

コマンド・関数名 動き
letコマンド let (変数名) = (値)で変数定義できます。
system()関数 (組み込み)シェルコマンドを実行し、実行結果の文字列を返します。
echoコマンド 引数の値を表示

これらのコマンドや関数については、:help let など、コマンド・関数名などの前に :help をつけて実行すると詳細なマニュアルが見られます:yum:

スクリーンショット 2017-12-03 17.17.09.png

2. lintでエラーが出た行数をハイライトしてみる

では、今度はエラーが出た行数をハイライトしてみましょう。
(Syntaxチェックは必ずしも正しい行数を出してくれるわけではないが、今回はlineを信じて表示する)

~/.vimrc
function! PHPLint()
    let result = system('php -l ' . bufname(""))
    let error_list = matchlist(result, '\(line \)\(\d\+\)', 1)
    if empty(error_list)
        echo "エラーはありませんでした"
        return
    endif
    call matchaddpos("Error",[str2nr(error_list[2])])
    echo result
endfunction

→保存・コマンドモードで以下を実行
:source ~/.vimrc

コマンド・関数名 動き
matchlist()関数 (組み込み)正規表現でマッチした文字列のリストを返します。
str2nr()関数 (組み込み)文字列を数値に変換した結果を返します。
matchaddpos()関数 (組み込み)第二引数に指定された行数を強調表示する

同じく、詳細は:help (関数名)で確認!

matchstr()で PHPのSyntaxエラー

Parse error: parse error in test.php on line 6
Errors parsing test.php

line XXXXXXを正規表現で取得し、その行をハイライトしています。

おい、:sourceできないぞ

はい。こんな表示が出たかと思います

Error detected while processing /path/to/.vimrc:
line  (行数):
E122: Function PHPLint already exists, add ! to replace it

関数は、function!で宣言しないと
再度:source コマンドを実行する事ができません。
リローダブルなvimrcを書くには、

function! PHPLint()
...
endfunction

とする必要があります(後述のautocmdも同様)。

matchaddpos の第一引数について

:help matchaddposすると、以下のようなシグネチャになっています。

matchaddpos({group}, {pos}[, {priority}[, {id}[, {dict}]]])

matchadd と同じである、ということで、matchadd のマニュアルを読んでみると、

{group} = 構文グループ

だとわかりますが、構文グループとはなんぞや:question:
ということで、さらに :help group と実行してみると、謎が解けます。

構文グループとは、同じ種類の構文アイテムをグループ化したものである。構文グルー
プから強調グループにリンクされ、強調グループに対して色が設定される。構文グルー
プそれ自体は、色や属性を指定するものではない。

なるほど。と、その下を読み進めていると、構文グループが列挙してありました。

スクリーンショット 2017-12-03 17.52.57.png
(つづく)

今回は下の方にあった、構文グループ ERROR を選択し、
指定した行数を ERROR と同じ強調色にしています。

こんな感じで、:help を使いこなすにはちょっとしたコツが必要ですが
慣れてくるとスルメのようにいい味が出てくるマニュアルです。

気を取り直して

コマンドモードで
:call PHPLint() を実行

すると、こうなります。

スクリーンショット 2017-12-03 18.22.52.png

3. 上記を保存時に実行できるようにする

~/.vimrc
autocmd! BufWritePost *.php :call PHPLint()

→保存・コマンドモードで以下を実行
:source ~/.vimrc

例によって :help autocmd してみると

:au[tocmd] [group] {event} {pat} [nested] {cmd}

コマンドの定義方法が出てきます。
(Vim script上でコロン(:)コマンドを書くときは、:は不要です。)
引数として必要なのは、{event}{pat}{cmd}だということがわかります。

autocmd はフックのようなものです。
{event}で指定されたイベントが発生したとき、{pat} で指定したファイルに対し、
{cmd}で指定したコマンド/関数を実行します。

{event} は、あらかじめVimに文字列で指定されています。
というわけで :help event を見てみましょう。

スクリーンショット 2017-12-03 18.11.06.png

いっぱい出てきました。
ここにあるイベント発生時に、任意のコマンドを実行できます。

BufWritePost

はバッファを保存した後のタイミングで実行するコマンドです。
test.php:w で保存してみましょう。PHPLint()が保存時に実行されているのがわかりますね。

おまけ:強調表示を消す方法

コマンド実行すると、強調表示されたままになってしまいます。
clearmatches() を実行すると強調表示がクリアされるので、以下のようにすると
シンタックスエラーがなくなれば表示も消えます。

function! PHPLint()
    let result = system( 'php -l ' . bufname(""))
    let error_list = matchlist(result, '\(line \)\(\d\+\)', 1)
    if empty(error_list)
        call clearmatches() ' ←こいつを追加
        echo "エラーはありませんでした"
        return
    endif
    call matchaddpos("Error",[str2nr(error_list[2])])
    echo result
endfunction

→保存・コマンドモードで以下を実行
:source ~/.vimrc

test.phpを正しく編集し、保存してみましょう。
強調表示が消えるはずです。

最後に

いかがでしたでしょうか?
今回は「作って覚える」ということで、細かい説明を省き
:helpを調べながら進めていきました。

Vim scriptと仲良くなるには、:helpと仲良くなるのが近道です。
楽しいVimライフを! & Merry Christmas!:christmas_tree: