初めてのプラグインを作る

はじめに

Meguro.vim#8に参加してプラグインを作りました

Meguro.vim#8

megurovim.connpass.com

f:id:kazu9su:20180218105314j:plain

景色がよい

やったこと

プラグインを作りました。

GitHub - kazu9su/vim-sweep_trail

Vim script テクニックバイブル ~Vim使いの魔法の杖

Vim script テクニックバイブル ~Vim使いの魔法の杖

内容的にはVim scriptテクニックバイブルの5章ですね。 ここで、プラグイン公開の章で練習問題的なものがあったのでもくもくとやってみました。

などのプラグイン作成における基本を抑えることができます。 さらに練習問題(?) として、下記のような追加機能の提案がありました。

  • 有効化/無効化を切り替えるコマンドを追加
  • 全角スペース対応
  • 指定した範囲のみの行末スペースを削除
  • 自動削除機能をバッファローカルに有効化/無効化できるように
  • 空行でインデントのみの行は削除しないようにするオプション追加

一つ一つ実装していきましょう。レッツトライ!

有効化/無効化を切り替えるコマンドを追加

具体的にやることとしてはglobal変数である g:sweep_trail#enable の値を切り替えるだけです。

:SweepTrailEnable, :SweepTrailUnable という2つのコマンドを作りました。

command! -bar SweepTrailEnable call sweep_trail#enable()
command! -bar SweepTrailUnable call sweep_trail#unable()
function! sweep_trail#enable()
    let g:sweep_trail#enable = 1
endfunction

function! sweep_trail#unable()
    let g:sweep_trail#enable = 0
endfunction

具体的な処理としては、1, 0をセットしているだけです。

全角スペース対応

次に全角スペースに対応しましょう。グループ(半角or全角スペース)でマッチするよう正規表現を更新します。

%ssubstitute/\(\s\| \)\+$//e

指定した範囲のみの行末スペースを削除

いきなり難易度が上がります。
まずはコマンド登録の際、選択行を取得できるようにします。具体的には range オプションを指定します。

command! -bar -range=% SweepTrail <line1>,<line2>call sweep_trail#sweep()

range=% 指定で、行が選択されていなかった場合、ファイル全体が選択されるようになります。
また、callに <line1>,<line2> を引数として渡すことで、呼び出した関数内で、 a:firstline, a:lastline として、選択行を取得できるようになるので、これを正規表現に利用します。
vimだと正規表現に範囲を指定できるのが、当たり前ですがテキストエディタぽいなーと思います。

function! sweep_trail#sweep() range
    execute printf('%s,%ssubstitute/\(\s\| \)\+$//e', a:firstline, a:lastline)
endfunction

こんな感じですね。まず range の指定で、選択行を取得できるようになります。
さらにprintfで変数を文字列に変換し、さらにexecuteに渡して実行します。

自動削除機能をバッファローカルに有効化/無効化できるように

未対応です><

空行でインデントのみの行は削除しないようにするオプション追加

これは色々と考えさせられました。が、最も地道な方法でいくことにしました。(時間もないので)

  1. 別の変数を用意し、その変数の操作によって切り替えを可能にし、
  2. 関数も専用のものを作る

という感じです。具体的に見ていきましょう。

有効無効の切り替え

command! -bar SweepTrailOptionEnable call sweep_trail#option_enable()
command! -bar SweepTrailOptionUnable call sweep_trail#option_unable()
function! sweep_trail#option_enable()
    let g:sweep_trail#option_enable = 1
endfunction

function! sweep_trail#option_unable()
    let g:sweep_trail#option_enable = 0
endfunction

サクサクいきましょう

関数も専用のものを作る

function! sweep_trail#sweep_optional() range
    execute printf('%s,%ssubstitute/\%(\S\+\)\@<=\(\s\| \)\+$//e', a:firstline, a:lastline)
endfunction

正規表現をがんばる必要がありました。
直前にスペース以外の文字が一文字以上存在したあとにスペースが続くパターンにマッチします。
肯定後読み。

参考

github.com 便利

終わりに

それなりに動くものが出来た気がします。本の中の人 もいるので質問もはかどり便利でした。
ありがとうございます。