Neovim 内の terminal の中から Neovim を操作する


今回は前回の記事と違い、Neovim 専用の話題です。

Neovim 内の端末で操作しているとき、「このディレクトリーを起点として Vim コマンドを実行したいな」なんて事がよくあります。より具体的には、「カレントディレクトリーを渡して denite を起動したい」と思ったんですね。

いくつか方法はあると思うのですが、これを以下のように実現することを考えました。

  1. ディレクトリーを移動する度に Neovim にディレクトリー名を通知する。
    • zsh の $chpwd_functions を使います。
    • bash では無理っぽい?1
  2. 端末内(Terminal-Job モード)で特定のキーを押したら保存したカレントディレクトリー名で denite を起動する。

Neovim の公式 Wiki を見ますととにかくありとあらゆる言語で Neovim を操作出来ることが分かります。今回は(多分)一番メジャーな Python で書いてみました。

Python で Neovim に接続する

neovim-client モジュールを使います。予めインストールしておきましょう。

pip3 install neovim

さて、Neovim への接続には attach 関数を利用します。$NVIM_LISTEN_ADDRESS という環境変数に Socket ファイルへのフルパスが渡されていますのでこれを使いましょう。

neovim_pwd.py
import os
from neovim import attach

nvim = attach('socket', path=os.environ['NVIM_LISTEN_ADDRESS'])

後は command メソッドで Vimscript を実行出来ます。

neovim_pwd.py
nvim.command('let b:__pwd__ = "{}"'.format(os.getcwd()))

これだけです。実際にはディレクトリー名のエスケープや環境変数が設定されていなかったときの対応も必要です。完全版のソースはここに置いています。

後はこの Python スクリプトを zsh に設定するだけです。

.zshrc
neovim-pwd() {
  (( $+commands[neovim_pwd.py] )) && neovim_pwd.py
}
if [[ -n $NVIM_LISTEN_ADDRESS ]]; then
  neovim-pwd
  chpwd_functions+=( neovim-pwd )
fi

このように .zshrc に追記しておくと、Neovim 内の端末でのみ、カレントディレクトリーを Neovim に通知してくれるようになります。後は Vim 側でこれを使うだけですね。

.vimrc
" ステータスラインにカレントディレクトリーを表示します
tnoremap <A-z><A-z> <C-\><C-n>:echo 'pwd is ' . b:__pwd__<CR>i
noremap  <A-z><A-z> :echo 'pwd is ' . b:__pwd__<CR>
" カレントディレクトリーから denite を起動します
tnoremap <A-z><A-n> <C-\><C-n>:call denite#start([{'name': 'file', 'args': ['', b:__pwd__]}])<CR>
noremap  <A-z><A-n> :call denite#start([{'name': 'file', 'args': ['', b:__pwd__]}])<CR>

見事、端末内からカレントディレクトリーが通知出来ています。直接 denite も起動可能です。便利ですね。