pockestrap

Programmer's memo

Vim in Vim しない :terminal

PoCを作っている。

なに

Vimには:terminalという便利なコマンドがあり、これを実行するとVimの中でターミナルが開く。1 これは多分便利で、例えばターミナルからgfしやすかったりすると思う。

:terminalコマンドで開かれるのはターミナルなので、もちろんそのターミナルからVimを起動することもできる。 これは面白いのだけど面白い以上の価値はあまりないと思っていて、何故ならばVimの中でVimを開くと単純に混乱する。

f:id:Pocke:20190323000948g:plain
Vim in VIm

そこで、Vim:terminalの中でVimコマンドを実行すると、外側のVimでファイルを開くようにしてみた。

f:id:Pocke:20190323001030g:plain
Vim in Vimではない

GIFを見てもいまいち分かりづらいと思うが、前者のGIFではVimの中のターミナルの中でVimが開いているのに対して、後者のGIFでは外側のVimの中で新しくWindowが立ち上がってファイルが開かれている。

実装

パスの通ったところにtvimとして保存する。Rubyは2.4以上ぐらいで動くと思う。2

#!/usr/bin/env ruby

def main(argv)
  if ENV['VIM_TERMINAL']
    servername = ENV['VIM_SERVERNAME']
    raise "Please add the following to your vimrc: `call remote_startserver('tvim')`" unless servername
    start_tvim(argv, servername: servername)
  else
    exec('vim', *argv)
  end
end

def start_tvim(argv, servername:)
  require 'optparse'
  opt = OptionParser.new
  params = {}
  opt.on('--tab')
  args = opt.parse(argv, into: params)
  if params[:tab]
    args.unshift('--remote-tab') 
  else
    args.unshift('--remote') 
  end
  exec('vim', '--servername', servername, *args)
end

main(ARGV)

.vimrcに次を追記する

call remote_startserver('tvim')

仕組み

まず、:terminalで起動されたシェルの中ではVIM_TERMINALVIM_SERVERNAMEという環境変数が追加される。3 そのためこれらの変数の存在を見ることで「今Vimのターミナルの中にいるか」が判定できる。

外側のVimでファイルを開くためには、Vim+clientserverを利用する。 これはVimの外からVimを操作するための機能である。

この機能を使うにはターミナルを立ち上げる前にremote_startserver()関数を呼び出して、サーバーを立ち上げておく必要がある。 またVimの中のターミナルからサーバー名を取得する必要があるが、それは前述のVIM_SERVERNAME環境変数から取得できる。

展望

  • しばらく使ってみて本当に便利なのか考える
  • bashかGoあたりで書き直す
  • 標準入力を開けるようにする
  • インターフェイスを練る

使ってみたり感想をもらえたりすると嬉しい。

追記 2019/03/23 14:15

vim-jpのSlackで、mattnさんにTapiという機能を教えてもらった。

qiita.com

+clientserverを使うよりもこちらを使ったほうが素直な実装ができそうなので、そのうち実装を更新してみる。


  1. 私は最近使いはじめて、まだ使いこなせていない。

  2. 広くリリースする時にはRubyの依存は外すと思う

  3. https://vim-jp.org/vimdoc-ja/terminal.html#terminal-unix