この記事は Vim Advent Calendar 2016 の21日目の記事です。凡人と申します。よろしくお願いいたします。
前回までのこと
やったこと
vimプラグイン作成に慣れるために、まずは「vimプラグインを作るためにやらなければならない必要最小限なこと」だけをやりました。
初めてのvimプラグイン作成 - 最小限なvimプラグイン
反省
しかしどうやらvimプラグインには、作るときのお作法があるとのことです。いくら最小限のvimプラグインだとしてもそれを反故にするのはどうかなと思いました。
反省を踏まえて、どうするのか
お作法を守りつつ、最小限のvimプラグインを作ることにします。
続・初めてのvimプラグイン作成 - 最小限なvimプラグイン
目的
お作法を守りつつも最小限なvimプラグインを作ります
するべきお作法の一覧
目的を達成するために、実装するべきお作法を列挙しておきます。
- お作法1:スクリプトファイルのエンコーディング指定
- お作法2:ユーザー設定を一時的に無効化する
- お作法3:autoloadの仕組みを使う
- お作法4:グローバル変数による読み込み制御
- お作法5:READMEを書く
プラグインの名前決め
「お作法を守ったきれいな世界へ飛び出そう」という願いを適当にこめて"hello-beautiful-world"という名前のプラグインにします。
ファイルとフォルダの構成
必要最小限のファイルとフォルダの構成です。
前回との違いは、autoloadフォルダとREADME.mdを用意しているところです。
hello-beautiful-world-vim
+- autoload
+- hellobeautifulworld.vim
+- plugin
+- hellobeautifulworld.vim
+- README.md
処理を決める
スクリプトの中心で世界を叫ぶのです。
:nmap z :echo "Hello World!"<CR>
お作法1:スクリプトファイルのエンコーディング指定
vimのスクリプトファイルが指定したエンコーディングで読み込まれることを保証します。
” エンコーディングの指定を各スクリプトの最初に書きます。
scriptencoding utf-8
お作法2:ユーザー設定を一時的に無効化する
ユーザー設定があると、いろいろ不都合がでるかもしれません。一時的にそれらを退避し、処理が終わったら戻します。
" ユーザー設定を一時退避
let s:save_cpo = &cpo
set cpo&vim
” ここにHello World
" 退避していたユーザ設定を戻す
let &cpo = s:save_cpo
unlet s:save_cpo
お作法3:autoloadの仕組みを使う
ファイルとフォルダの構成を見ると、hellobeautifulworld.vimというファイルがpluginフォルダとautoloadフォルダにそれぞれ用意されています。
hello-beautiful-world-vim
+- autoload
+- hellobeautifulworld.vim
+- plugin
+- hellobeautifulworld.vim
+- README.md
これは、それぞれ役割が異なります。
- plugin以下は、vim起動時に呼ばれるスクリプトファイルです。
- autoload以下は、必要になったタイミングで読み込まれるスクリプトファイルです。
よって、vimプラグインでは、次のようにします。
- plugin以下のスクリプトでは、関数呼び出し処理を書く
- autoload以下のスクリプトでは、呼び出される関数を書く
こうすることで、使うかどうかわからない関数読み込みを省略します。
今回のように「Hello World!」を表示するだけの処理はこんなことをする必要性は全くありませんが、仕方がありません。美しい世界のためです。
よって、HelloWorldを関数化し、それを呼び出すようにしておきます。
” 関数コール(plugin以下のスクリプトに書く)
nmap z :call hellobeautifulworld#helloworld()<CR>
" 関数の定義(autoload以下のスクリプトに書く)
function! hellobeautifulworld#helloworld()
echo "Hello World!"
endfunction
関数名は、[プラグイン名]#[関数名]と定義しておく必要があるとのことです。これに従い 「hellobeautifulworld#helloworld」という関数名にしました。
お作法4:グローバル変数による読み込み制御
グローバル変数を使うことで、各スクリプトの読み込み処理を制御します。グローバル変数の名前は、[g:loaded_プラグイン名]とするのがお作法とのようです。
よって、ここではg:loaded_hellobeautifulworld という名前にします。
plugin以下のスクリプトと、autoload以下のスクリプトでは、制御が異なります。私はうっかり同じ制御をコピペしてしまい、ハマりました。
plugin以下のスクリプトでは、2回以上は読み込まないように条件を書きます。
" (plugin以下のスクリプトに書く)
" 読み込み制御用の変数がすでに存在していたら、もうすでに読み込み済みと判断して終了する
if exists('g:loaded_hellobeautifulworld')
finish
endif
let g:loaded_hellobeautifulworld = 1
autoload以下のスクリプトでは、plugin以下のスクリプトが読み込まれていることを確認するための条件となります。
" 読み込み制御用の変数が存在していないのであれば、
" plugin以下のスクリプトが読み込まれていないと判断できるため、終了する。
if !exists('g:loaded_hellobeautifulworld')
finish
endif
let g:loaded_hellobeautifulworld = 1
お作法5:READMEを書く
READMEは充実させるべきではありますが、今回はインストール方法と使い方だけを最低限として書いておきましょう。(今回書いたREADMEが最小限すぎるので省略します)
書いたvimスクリプト
実際に書いたvimスクリプトファイルは次のようになります。
scriptencoding utf-8
if exists('g:loaded_hellobeautifulworld')
finish
endif
let g:loaded_hellobeautifulworld = 1
let s:save_cpo = &cpo
set cpo&vim
nmap z :call hellobeautifulworld#helloworld()<CR>
let &cpo = s:save_cpo
unlet s:save_cpo
autoloadの下にある"hellobeautifulworld.vim"
scriptencoding utf-8
if !exists('g:loaded_hellobeautifulworld')
finish
endif
let g:loaded_hellobeautifulworld = 1
let s:save_cpo = &cpo
set cpo&vim
function! hellobeautifulworld#helloworld()
echo "Hello World!"
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo
GitHubへアップロード
上記のファイルとフォルダでgitのリポジトリを作成し、GitHubへアップロードします。
プラグインとして設定する
READMEに従い、vimrcに次の記述を追加します。
NeoBundle 'bonjin6770/hello-beautiful-world.vim'
プラグインのインストール
vimを起動し、プラグインをインストールします。
:NeoBundleInstall
プラグインの実行
vimのノーマルモード時に、[z]キーを押します。
なにはともあれ成功です。
スクリーンショットとしては恐ろしいほど前回と全く同じです。ただし、今回は関数をコールしているため、一瞬関数コールの文字が見えました。
まとめ
「vimプラグイン作成」が、自分の中で非常にハードルが高く、二の足を踏んでいました。しかし、前回と今回のように非常に簡単なものから作ることで、そのハードルを下げることに成功しました。
しかし、お作法を考えてvimプラグインを作ると、前回のように「非常にシンプル!超簡単!!」とはいきませんでした。
そしてやはり初心者の私にとって、お作法はちょっ難しく感じました。
もし初めてのvimプラグイン作りが、これらのお作法から覚えていくとなるとちょっと億劫だっただろうなと思います。
vimスクリプトをちゃんと書くこと自体が初めてですが、楽しく書くことができてよかったです。(実はvimスクリプトでの関数定義すら知らなかったので、色々試行錯誤しています。それも含め楽しかったです。)
なにぶん初めてのプラグイン作成なので、至らぬ点などがあるかもしれません。ご指摘があれば、是非よろしくお願いします。