1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Vimのプラグイン作成に入門した話

Posted at

はじめに

こんにちは、ひがしです。
最近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で入力された文字が補完対象の文字かを判断し、関数の返り値にinputObjectcompObjectの対応する要素と<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

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?