普段、テキストエディタとして、私はVimを使っています。
括弧の補完機能を便利にしたいと思い、今回はそれを自作してみようと思います。
今回作成する補完機能について
今回作る、括弧やクォーテーションの補完機能は、だいたい次のようなふうになります。
- 括弧を入力したとき、対応した閉じ括弧を自動的に入力する
- 閉じ括弧が入力されたとき、カーソルの後ろに閉じ括弧があれば、入力せずにカーソルを右に移動する
- クォーテーションが入力されたとき、場合に応じて、入力せずにカーソルを右にずらしたり、2つ入力したりする
- 改行されたとき、カーソルの前後に括弧があったら、括弧の中心の行にカーソルを移動して、インデントをつける
- スペースキーが押されたとき、カーソルの前後に括弧があったら、スペースを2つ入力する
- 削除キーが押されたとき、カーソル前後のスペースや括弧を同時に削除
- 文字列を選択して括弧を入力することで、その文字列を括弧で挟む
- 文字列を選択してクォーテーションを入力することで、その文字列をクォーテーションで挟む
では、順番に作っていきましょう。
まず最初のこのページでは、この補完機能を作るための便利な関数を作っていきます。
※今回はJavaScriptのファイル(.js)で試しています。他の形式だと、動きが変わってしまったりします。
カーソル前後の文字列を取得する関数
補完機能を作るためには、カーソルの前後の文字がなにか、が重要になります。
そこで、カーソル前後の文字列を取得する関数を作っていきましょう。
まずは、カーソルの次の文字列を取得する関数です。
"カーソルの次の文字列を取得(引数は取得したい文字数)
function! GetNextString(length) abort
let l:str = ""
for i in range(0, a:length-1)
let l:str = l:str.getline(".")[col(".")-1+i]
endfor
return l:str
endfunction
この関数の引数には、取得したい文字数を指定します。
"カーソルの前の文字列を取得(引数は取得したい文字数)
function! GetPrevString(length) abort
let l:str = ""
for i in range(0, a:length-1)
let l:str = getline(".")[col(".")-2-i].l:str
endfor
return l:str
endfunction
さきほどのものと同様に、引数には、取得したい文字数を指定します。
アルファベット、数字、全角文字かどうかを判定する関数
補完機能を作る上で、もうひとつとても重要なものがあります。
それは、その文字が、アルファベットなのか、数字なのか、全角文字なのか、といった判定がです。
そういった判定は、正規表現を使います。
"アルファベットかどうかを取得
function! IsAlphabet(char) abort
let l:charIsAlphabet = (a:char =~ "\a")
return (l:charIsAlphabet)
endfunction
"全角かどうかを取得
function! IsFullWidth(char) abort
let l:charIsFullWidth = (a:char =~ "[^\x01-\x7E]")
return (l:charIsFullWidth)
endfunction
"数字かどうかを取得
function! IsNum(char) abort
let l:charIsNum = (a:char >= "0" && a:char <= "9")
return (l:charIsNum)
endfunction
どの関数も、引数には判定したい文字を指定します。
また、数字かどうかの判定では、数字の「文字」の判定をしたかったので、正規表現は使いませんでした。
カーソルの左右に括弧があるかどうかを取得する関数
つづいて、カーソルの左右に括弧があるかどうかを判定できる関数を作っていきます。
"括弧の中にいるかどうかを取得
function IsInsideParentheses(prevChar,nextChar) abort
let l:cursorIsInsideParentheses1 = (a:prevChar == "{" && a:nextChar == "}")
let l:cursorIsInsideParentheses2 = (a:prevChar == "[" && a:nextChar == "]")
let l:cursorIsInsideParentheses3 = (a:prevChar == "(" && a:nextChar == ")")
return (l:cursorIsInsideParentheses1 || l:cursorIsInsideParentheses2 || l:cursorIsInsideParentheses3)
endfunction
引数にはカーソルの前と後の文字をひとつずつ指定します。
ここまでで、括弧やクォーテーションの補完に必要な機能を作ることができました。
次のページから、ここまでで作った関数を使って、実際に補完機能を作っていきます。