ここまでで、括弧やクォーテーション補完に必要な機能を作りました。
このページでは、ここまでで作った機能を使って、まずは括弧の補完機能を作ります。
閉じ括弧を自動入力
まず、括弧を入力したときに、それに対応した閉じ括弧を自動的に入力するようにします。
しかし、ただ閉じ括弧を自動的に入力するだけでは、使いにくいものになってしまいます。
そこで、3つの条件をクリアしたときのみ、自動的に閉じ括弧を入力するようにします。
- カーソルの後ろの文字が、なにもないとき(行末のとき)
- カーソルの後ろの文字が、閉じ括弧のとき
- カーソルの後ろの文字が、空白のとき(半角スペースのとき)
上記のような条件をつけることで、とても使いやすくなります。
さらに、閉じ括弧の入力後は、カーソルを括弧の中に移動したいです。
そうすることで、括弧を入力したあと、わざわざカーソルをひとつ戻すことなく、そのまま入力を続けることができます。
"括弧の入力
function! InputParentheses(parenthesis) abort
let l:nextChar = GetNextString(1)
let l:prevChar = GetPrevString(1)
let l:parentheses = { "{": "}", "[": "]", "(": ")" }
let l:nextCharIsEmpty = (l:nextChar == "")
let l:nextCharIsCloseParenthesis = (l:nextChar == "}" || l:nextChar == "]" || l:nextChar == ")")
let l:nextCharIsSpace = (l:nextChar == " ")
if l:nextCharIsEmpty || l:nextCharIsCloseParenthesis || l:nextCharIsSpace
return a:parenthesis.l:parentheses[a:parenthesis]."\<LEFT>"
else
return a:parenthesis
endif
endfunction
また、この関数は括弧を入力したときに呼び出したいので、以下のものも追加します。
inoremap <expr> { InputParentheses("{")
inoremap <expr> [ InputParentheses("[")
inoremap <expr> ( InputParentheses("(")
閉じ括弧を入力したときの動きを変更
つづいて、閉じ括弧の入力のときも、そのままではちょっと使いにくいです。
プログラミングをしていると、括弧の中になにも入力しないことはよくあります。
そのときは、括弧の入力時にカーソルが括弧の中に移動する機能が、煩わしく感じるときがあるんです。
方向キーの右を押す手もありますが、Vimでは方向キーを使ってはいけないのです。(たぶん諸説あり)
そこで、カーソルの後ろに閉じ括弧がある場合のみ、閉じ括弧が入力されずにカーソルが右に動く、というふうにしていきます。
では、作っていきましょう。
"閉じ括弧の入力
function! InputCloseParenthesis(parenthesis) abort
let l:nextChar = GetNextString(1)
if l:nextChar == a:parenthesis
return "\<RIGHT>"
else
return a:parenthesis
endif
endfunction
引数には、入力する閉じ括弧を指定します。
また、この関数は閉じ括弧を入力したときに呼び出したいので、以下のものも追加します。
inoremap <expr> } InputCloseParenthesis("}")
inoremap <expr> ] InputCloseParenthesis("]")
inoremap <expr> ) InputCloseParenthesis(")")
クォーテーションの入力
つづいて、クォーテーションを入力したときの補完機能を作っていきます。
クォーテーションの入力は、括弧の入力のときよりも、ほんの少し複雑になります。
では、クォーテーションを入力するときの条件を確認しておきましょう。
今回、クォーテーションの入力は、以下のような条件にしました。
- カーソルの左右にクォーテーションがあるとき、カーソルを右に移動する
- カーソルの前の文字が、アルファベット、数字、全角文字、クォーテーションのとき、クォーテーションを入力
- カーソルの後ろの文字が、空(行末)、閉じ括弧、空白(半角スペース)のとき、クォーテーションを2つ入力してカーソルを中心に移動する
- 上記のどれでもないときも、クォーテーションを入力
"クォーテーションの入力
function! InputQuot(quot) abort
let l:nextChar = GetNextString(1)
let l:prevChar = GetPrevString(1)
let l:cursorIsInsideQuotes = (l:prevChar == a:quot && l:nextChar == a:quot)
let l:nextCharIsEmpty = (l:nextChar == "")
let l:nextCharIsClosingParenthesis = (l:nextChar == "}" || l:nextChar == "]" || l:nextChar == ")")
let l:nextCharIsSpace = (l:nextChar == " ")
let l:prevCharIsAlphabet = IsAlphabet(l:prevChar)
let l:prevCharIsFullWidth = IsFullWidth(l:prevChar)
let l:prevCharIsNum = IsNum(l:prevChar)
let l:prevCharIsQuot = (l:prevChar == "\'" || l:prevChar == "\"" || l:prevChar == "\`")
if l:cursorIsInsideQuotes
return "\<RIGHT>"
elseif l:prevCharIsAlphabet || l:prevCharIsNum || l:prevCharIsFullWidth || l:prevCharIsQuot
return a:quot
elseif l:nextCharIsEmpty || l:nextCharIsClosingParenthesis || l:nextCharIsSpace
return a:quot.a:quot."\<LEFT>"
else
return a:quot
endif
endfunction
また、クォーテーションが入力されたときに、この関数を呼び出すように、以下のものを追加します。
inoremap <expr> ' InputQuot("\'")
inoremap <expr> " InputQuot("\"")
inoremap <expr> ` InputQuot("\`")
改行(return, enter)の入力
つづいて、改行(return, enter)が入力されたときの補完機能を作っていきます。
どういったものを作りたいのかというと、カーソルが括弧で挟まれているとき、改行すると閉じ括弧がもう1段下にいき、括弧の間の行にカーソルが来るようにしたいのです。
これを作ると、つぎのようになります。
"改行の入力
function! InputCR() abort
let l:nextChar = GetNextString(1)
let l:prevChar = GetPrevString(1)
let l:cursorIsInsideParentheses = IsInsideParentheses(l:prevChar,l:nextChar)
if l:cursorIsInsideParentheses
return "\<CR>\<ESC>\<S-o>"
else
return "\<CR>"
endif
endfunction
また、returnやenterが押されたときに、この関数を呼び出すように、次のものを追加します。
inoremap <expr> <CR> InputCR()
スペース(space)の入力
つづいて、スペースキーが入力されたときの補完機能を作っていきます。
プログラミングをしていると、括弧の内側の両端にスペースを入れたいときがあると思います。
これは、人によっては見づらいと感じるかもしれませんが、私はこのスペース、見やすくて好きです。
そこで、カーソルの前後の括弧があるときスペースを入力すると、2つスペースが入力され、カーソルがその中心に移動するようにしたいと思います。
"スペースキーの入力
function! InputSpace() abort
let l:nextChar = GetNextString(1)
let l:prevChar = GetPrevString(1)
let l:cursorIsInsideParentheses = IsInsideParentheses(l:prevChar,l:nextChar)
if l:cursorIsInsideParentheses
return "\<Space>\<Space>\<LEFT>"
else
return "\<Space>"
endif
endfunction
スペースキーが押されたとき、この関数を呼び出すようにするため、つぎのものを追加します。
inoremap <expr> <Space> InputSpace()
削除キー(delete, backspace)の入力
つづいて、削除キー(delete, backspace)が入力されたときの補完機能です。
さきほど、括弧を入力するとき、自動的に閉じ括弧が入力されるようにしました。
さらに、括弧のなかでスペースを入力すると、カーソルの前後にスペースが入力されるようにもしました。
もちろん、それを削除するときも、カーソル前後のスペースや括弧を、一度に削除したいですよね。
"バックスペースの入力
function! InputBS() abort
let l:nextChar = GetNextString(1)
let l:prevChar = GetPrevString(1)
let l:nextTwoString = GetNextString(2)
let l:prevTwoString = GetPrevString(2)
let l:cursorIsInsideParentheses = IsInsideParentheses(l:prevChar,l:nextChar)
let l:cursorIsInsideSpace1 = (l:prevTwoString == "{ " && l:nextTwoString == " }")
let l:cursorIsInsideSpace2 = (l:prevTwoString == "[ " && l:nextTwoString == " ]")
let l:cursorIsInsideSpace3 = (l:prevTwoString == "( " && l:nextTwoString == " )")
let l:cursorIsInsideSpace = (l:cursorIsInsideSpace1 || l:cursorIsInsideSpace2 || l:cursorIsInsideSpace3)
let l:existsQuot = (l:prevChar == "'" && l:nextChar == "'")
let l:existsDoubleQuot = (l:prevChar == "\"" && l:nextChar == "\"")
if l:cursorIsInsideParentheses || l:cursorIsInsideSpace || l:existsQuot || l:existsDoubleQuot
return "\<BS>\<RIGHT>\<BS>"
else
return "\<BS>"
endif
endfunction
さらに、削除キーが押されたときにこの関数を呼び出すように、つぎのものを追加します。
inoremap <expr> <BS> InputBS()
また、この機能を使うためには、以下のものを追加して、バックスペースの機能を柔軟にしておきましょう。
多くの方は.vimrc
に追加していると思います。
set backspace=indent,eol,start
つぎのページでは、括弧やクォーテーションの入力がもっと便利になるようなコマンドを追加していきます。