はじめに
こんにちは、ひがしです。
最近Vimのプラグイン作成に興味がでてきてそれでプラグインを作成しました。
Kakkonanという名前の括弧補完プラグインです。
実装の話を書いていこうと思います。
ユーザー設定の無効化
Vimのプラグインを作っていく上でユーザーの使っている設定と自分の書いたプラグインのコードが衝突する場合があります。
それを一時無効化して処理が終わったら戻す処理を書きます。
let s:save_cpo = &cpo
set cpo&vim
let &cpo = s:save_cpo
unlet s:save_cpo
入力を受け付ける
今回はinoremap
を使い、入力を受け付けることにしました。
()
,{}
,""
,''
,[]
を補完対象にしたいので
inoremap <expr> ( Completion('(')
inoremap <expr> { Completion('{')
inoremap <expr> [ Completion('[')
inoremap <expr> " Completion('"')
inoremap <expr> ' Completion("'")
と記述しました。
<expr>
の引数をつけることで関数を呼び出せます。
Completion()
関しては後述します
autoloadを使う
vimには必要になったときに読み込んでくれるautoloadという仕組みがあります。
それを使うのがプラグイン作成のマナーらしいのですが関数名の付け方が少し変わり、
普通に関数名をつけるのではなく
プラグイン名#関数名
とつけるらしいです。
括弧を補完してくれる関数を作る
括弧を保管するだけなら
inoremap { {}<left>
でもいい気がしますが、あとあと色々な機能を付け足したかったので関数化しました。
function! Completion(inputObject)
let canComp = ['(', '{', '[', '"', "'"]
let compObject = [')', '}', ']', '"', "'"]
let nowArrayPos = 0
for i in canComp
if i == a:inputObject
return a:inputObject.compObject[nowArrayPos]."\<left>"
endif
let nowArrayPos += 1
endfor
endfunction
canComp
で入力された文字が補完対象の文字かを判断し、関数の返り値にinputObject
とcompObject
の対応する要素と<left>
を返します。
括弧が消されたときにもう片方も消す動作
括弧が()
のように連続して続いて、(
の部分をバックスペースで削除した場合、その対応している括弧も消す機能が必要です。
function! DeleteChar()
let leftDelete = ['(', '{', '[', "'", '"']
let rightDelete = [')', '}', ']', "'", '"']
let cursorLeftChar = GetCursorChar(-2)
let cursorRightChar = GetCursorChar(-1)
let tmp = 0
for i in leftDelete
if i == cursorLeftChar
if cursorRightChar == rightDelete[tmp]
return "\<BS>\<right>\<BS>"
endif
endif
let tmp += 1
endfor
return "\<BS>"
endfunction
対応する括弧を消す部分は先程の括弧を補完する部分を少し変えただけです。
ただ対応した括弧を探すという部分の実装が難航しました。
カーソルのn文字前の文字を探す
先程の括弧を消す動作に必須なカーソルからn文字前の文字を取得する部分なのですが
function! GetCursorChar(diff)
let cursorStr = getline('.')
let cursorCol = col('.')
return cursorStr[cursorCol + a:diff]
endfunction
と実装しました。
vimではgetline('.')
でその行の文字列を取得することができます。
そこからcol('.')
でカーソルのある列番号を取得し、
getline('.')
で取得した文字列のcol('.') - n
も要素を取り出すことでn番目の文字を取得することができました。
できたもの
Kakkonanのリポジトリ
このリポジトリにおいてあります。
最後に
今は括弧が補完できるだけなので次はビジュアルモードで囲んだところを指定した括弧でくくれるようにしたいです
参考にした文献
https://vim-jp.org/vimdoc-ja/usr_41.html#41.11
https://vim-jp.org/vimdoc-ja/map.html
https://qiita.com/bonjin6770@github/items/31e60707ecf2ad6c4496