Quantcast
Channel: Vimタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 5608

Vim/Neovim の terminal mode の中で Vim/Neovim を実行するときに便利そうなやつを作った

$
0
0

つくった


画像は https://ghlinkcard.com/から生成
参考: みんなにOSSを見てもらいたい人の為に、GitHubリポジトリのOGP的画像を自動生成してくれるサービスを作った

どういうやつ?

Vim/Neovim の terminal mode で Vim/Neovim を実行すると Vim/Neovim が入れ子に起動してしまう
asciicast

これを回避するには Neovim の場合は mhinz/neovim-remoteを使うとよい
asciicast

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

どうやってつかう?

こんな感じ
asciicast

あとは 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_SERVERNAMEhogehogeと入っているので 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 を書いて、この挙動を実装する方針である


Viewing all articles
Browse latest Browse all 5608

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>