Vimで挿入モードに入ったり出たりした時にIMEをコントロールする

この記事はVim2 Advent Calendar 2017の19日の記事(代打)です。

この記事ではmacOS High Sierraでvimの挿入モードに入ったり、挿入モードから出た時にIMEの状態を自動で切り替える方法を説明します。
私はATOKを使っていますが、標準の日本語入力やGoogle IMEを使っていても少しの修正で使えると思います。
挙動としては、挿入モードを抜けた時にIMEの状態を記憶して、挿入モードに入ったときに復元する感じです。

まず最初に、環境設定>キーボード>入力ソースでお好みの英語の入力用ソースを追加します。私の場合はU.S.を追加しました。
結果として入力ソースは以下の画像のようになります。
入力ソース

そして、macOSのIMEをcliで切り替えたりできる、swim を入れます。
IMEを切り替えながら swim list --current を使って、日本語と英語のIMEの内部名称をメモしてください。

そんでもって、下記 Vim script を vimrc にどーん。
s:JapaneseIMs:AsciiIM の値は先ほどメモしたやつに書き換えてくださいね。

" input method
let s:JapaneseIM = 'com.justsystems.inputmethod.atok30'
let s:AsciiIM = 'com.apple.keyboardlayout.all'

function! s:ImActivateFunc(active)
  if a:active
    call system('swim use ' . s:JapaneseIM)
  else
    call system('swim use ' . s:AsciiIM)
  endif
endfunction

function! s:ImStatusFunc()
  return system('swim list --current') is# s:JapaneseIM . "\n"
endfunction

let s:ImStatus = 0

function! s:insertEnter()
  call s:ImActivateFunc(s:ImStatus)
  call s:ImStatusFunc()
endfunction

function! s:insertLeave()
  let s:ImStatus = s:ImStatusFunc()
  call s:ImActivateFunc(0)
  call s:ImStatusFunc()
endfunction

augroup ime
  autocmd!
  autocmd InsertEnter * call s:insertEnter()
  autocmd InsertLeave * call s:insertLeave()
augroup END

本当は、imafimsfを適切に設定すればvimがかってにうまいことやってくれるんですが、imsfは頻繁に呼ばれてしまい、それでvimがもたついてしまうので挿入モードに出入りするときだけ呼ぶようにしたのが上記になります。
macOS以外の人もImActivateFuncとかImStatusFuncを適切に実装すれば同じことができるはず?

Vimで快適な日本語執筆環境をめざして!

追記:
ImActivateFuncを呼んだ後にImStatusFuncを呼んでいるのは、swimがIMEの切り替えに失敗?することがあって、そんなときに swim list --current を呼んでやるとうまくいくというworkaroundです。