つくった

画像は https://ghlinkcard.com/ から生成
参考: みんなにOSSを見てもらいたい人の為に、GitHubリポジトリのOGP的画像を自動生成してくれるサービスを作った
どういうやつ?
Vim/Neovim の terminal mode で Vim/Neovim を実行すると Vim/Neovim が入れ子に起動してしまう
これを回避するには Neovim の場合は mhinz/neovim-remote を使うとよい
Vim8 の場合でも clientserver 機能や terminal-api を利用すればよい
参考(clientserver): Vim の :terminal の中から外の Vim を操る方法
参考(clientserver): :h clientserver
参考(terminal-api): :terminal に関する小さい Tips
参考(terminal-api): :h terminal-api
しかしいずれにせよ、vim/nvim の中と外で実行するコマンドを切り替えねばならんというのは面倒である
なので、自身が vim/nvim の中なのか外なのかをよしなに判断して上記の回避策を実行してくれるツールを作成した
先行研究もあったが、Vim8 のみ対応のようだったので Neovim にも対応する形で実装してみた
参考: Vim in Vim しない :terminal
どうやってつかう?
あとは alias vim=vimalter みたいな感じで shell の alias 登録すれば、どこでもとりあえず vim って実行すればいい感じに vim/nvim が開く
なにをしている?
vimalter コマンドを実行しているのは vim なのか nvim なのか shell なのか
vim/nvim は terminal mode のとき、いくつか環境変数を追加してくれているので、それを利用した
環境変数 VIMRUNTIME に runtimepath を入れてくれているようなので(ex. VIMRUNTIME=/usr/share/nvim/runtime)一つ上のディレクトリ(ex. /usr/share/nvim) の部分が nvim なのか vim なのかで判定した
もしかすると自前で vim/nvim を build してたりするとここに vim or nvim が入っておらず、上手く動かないかもしれない
neovim の場合
単純に引数を nvr コマンドに食わせて実行すればよい
vim の場合
vim は少し複雑で :term する前に call remote_startserver('hogehoge') を叩いているかどうかで挙動を変える必要がある
remote_startserver() は +clientserver オプションを付けて build された vim でしか実行できない関数で、引数に指定された名前(例では hogehoge)で vim サーバを起動するコマンドである
これが実行されていれば terminal mode では 環境変数 VIM_SERVERNAME に hogehoge と入っているので vim --servername $VIM_SERVERNAME --remote file_name というコマンドを実行すれば親の vim で file_name を開いてくれる
call remote_startserver('hogehoge') されていない場合は環境変数 VIM_SERVERNAME は空なので他の方法を考える必要がある
今回は terminal-api を利用した
terminal-api の詳細は先に挙げた参考資料に任せるとして、とにかく echo -e \x1b]51;[\"drop\",\"file_name\"]\x07 と terminal mode で実行すれば親の vim で file_name に指定したファイルを開いてくれる
vim の実行ファイルを探索する
/usr/bin/vim が vim だといつから錯覚していた?
はい、debian 系(というか update-alternatives を使用している場合などは大抵) /usr/bin/vim とはただのシンボリックリンクである
実態はどこにいるかは辿ってみないと分からないので雑に vim に引数を食わせるわけにはいかない
ちゃんと現在 terminal mode で実行中の vim の実 path を辿ってやる必要がある
方法は愚直に PPID を辿って vim または vim.basic(debian で apt で入れた vim の実行ファイル名はこれになる) という文字列が実行ファイル名になっているものを探す
apt でインストールされた vim の実行ファイル名は他にも vim.tiny とかもあるが、vim.tiny は terminal mode が使用できないので除外した
他にも実行ファイル名のパターンがあれば Issue か PR をください...!
この実装をする際 shirou/gopsutil が非常に便利だった
-tab option
Vim の --remote オプションは親でファイルを開く際、ファイルをウィンドウ分割して開く、という挙動となっており、個人的には --remote-tab の挙動のほうが好みだったので -tab オプションで制御できるようにした
弊害として、vim 側のオプションを渡す際は -- を付ける必要があるが、まあ大抵こういうコマンドはそうなってるのでいいかな、と(適当)
vim --remote-tab だと、既存に空ファイルのウィンドウがあればそのウィンドウでファイルを開き、それ以外の場合は新規に tab を作成してそこでファイルを開く、という挙動をする
このとき困るのは terminal-api での実装で、現状 drop コマンド(つまり挙動としては --remote と同じ)しか雑にファイルを開くときには使えないので --remote-tab を真似ることはできない
call コマンドというユーザ定義関数を呼ぶコマンドもあるにはあるが、Tapi_ で始まるユーザ定義関数しか呼べない、という制限があるため現状は未実装ということにしている
今後の予定として Tapi_ 関数群を提供する Vim plugin を書いて、この挙動を実装する方針である