4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Vimをターミナルマルチプレクサとして使うためにやったこと

Posted at

Vim 8 terminal job

Vim 8 からは terminal jobというVimのバッファ上でシェルを操作できる機能があります。

こちらなんですが、実はシェルを操作できるだけじゃなく、sshやNode.jsやClojureのreplなどttyを必要とするアプリケーションを指定するとバッファ上でそのままジョブが動いたりして便利です。

この記事ではこのterminal jobを利用した環境を魔改造カスタマイズしてより便利にしていく方法を紹介します。

この記事はbashを前提としています。

Vim上のbashからVimにコマンドを送れるようにする

Vimのclientserver機能

Vimにはclientserver機能があり、こちらを使うと他プロセスから対応するサーバ名のVimに対してコマンドを送信できます。

こちらを利用するためにはclientserver機能を有効にしたVimが必要です。

まずVim上で以下を実行します。

:call remote_startserver('mainecoon')

そして、ターミナル上(Vim上のものでも、他のものでも構いません)で、以下を実行します。

$ vim --servername mainecoon --remote-send '<C-w>:echo "hoge"<CR>'

すると、Vimには --remote-send で指定した <C-w>:echo "hoge"<CR> というキー入力が送信され、これにより :echo "hoge" が実行されます。

更に、clientserver機能を実行した状態で起動したアプリケーションの環境変数には VIM_SERVERNAME という値が追加されます。
よって、Vim上のbashでVimにキー入力を送信したい場合bashで以下のようなコマンドを実行すれば良いことがわかります。

$ vim --servername $VIM_SERVERNAME --remote-send '<C-w>:echo "hoge"<CR>'

ここまでのことを踏まえると以下のように .bashrc に追記することで、簡単なコマンドでVimにキー入力ができることが分かります。

if [ -n $VIM_SERVERNAME ]; then
    function v() {
        vim --servername $VIM_SERVERNAME --remote-send "<C-W>$*<CR>"
    }
fi

追記し、新たにVim上でbashを開くと

$ v :new hoge.md

などとすることでVim上のbashから新たなバッファを開き、そこで指定したファイルの編集を開始できます。

しかし

$ cd ./hoge ; v :new fuga.md

のような相対パスでのファイル指定は上手く実行できません。これはterminal jobのバッファのカレントディレクトリが起動時のカレントディレクトリのままになっているからです。

というわけで、指定コマンドの実行前に :lcd $PWD してあげることで解決します。
最終的に v という関数は以下のようになります。

if [ -n $VIM_SERVERNAME ]; then
    function v() {
        vim --servername $VIM_SERVERNAME --remote-send "<C-W>:lcd ${PWD}<CR>"
        vim --servername $VIM_SERVERNAME --remote-send "<C-W>$*<CR>"
    }
fi

毎起動時にclientserverを起動する場合は以下を .vimrc に記述してください(サーバ名は自由にしてください)

if has('clientserver') && len(v:servername) <= 0
    let server_list=split(serverlist(), '\n')
    let server_count=len(server_list)
     
    if match(server_list, v:servername) <= 0
        call remote_startserver('siberian' . server_count)
    endif
endif

注意事項

terminal jobが生きている状態では :e hoge.md はできないので、 :e! hoge.md しないといけません。我慢してください。

独自のエイリアスを定義し、Vimで対応するコマンドを実行する

人の欲は止まるところを知らず、Vim上で開いたbashから任意のVimコマンドにエイリアスをつけたくなります。

そこで、.bashrcに最高の関数を定義することで、無理矢理これを実現します。

エイリアス設定の形式

今回は

alies commands args...

のような形式でエイリアス設定を記述することにしました。

よって、Vim上のbashでvn というエイリアスで :new したい場合は

vn :new

という形になります。今回はこの設定ファイルを ~/.vimfuncrc に配置することにします(rcではないが書いた当初の気持ちでこのような命名になっています)

エイリアス設定からVimコマンド実行用のbash関数を生成する関数を .bashrc に書く

解説が大変なので先にスクリプトを貼ります。

if [ -n $VIM_SERVERNAME ]; then
    function v() {
        vim --servername $VIM_SERVERNAME --remote-send "<C-W>:lcd ${PWD}<CR>"
        vim --servername $VIM_SERVERNAME --remote-send "<C-W>$*<CR>"
    }
 
    function vFuncDeclare() {
        eval "function $1() {
            v `echo "$*" | cut -d' ' -f2-` "\$*"
        }"
    }
 
    VFUNCPROP=`sed -e 's/^/vFuncDeclare /g' ~/.vimfuncrc`
    VFUNCCOUNT=`wc -l <<EOF
$VFUNCPROP
EOF`
 
    for i in `seq 1 $VFUNCCOUNT`; do
    `head -$i <<EOF | tail -1
$VFUNCPROP
EOF`
    done
 
fi

重要なのは vFuncDeclare という関数で、これは

funcname :vim-func arg1 arg2 ...

の形式から

function funcname() {
  v :vim-func arg1 arg2 ... "$*"
}

という関数を定義する関数です。さらに、ここで定義された関数には追加の引数を与えることができます。

たとえば

vn :new

という定義をこの関数に渡すと

function vn() {
  v :new "$*"
}

という関数が定義されるので、Vim内のbashから

$ vn ./filename

とすると新しいバッファで ./filename を編集できます。

この vFuncDeclare の後のあれこれは .vimfuncrc の中身をなんとかして vFuncDeclare に渡すための記述です。

実際の設定例

vn :new
vt :tabnew
gt :tabnext
gT :tabprevious
wt T'<C-W>':Nop 
vterm :term 
Vterm :term $* '<CR><C-W>T<C-W>':Nop
vssh :term ssh
Vssh :term ssh $* '<CR><C-W>T<C-W>':Nop
Vemacs :term emacs -nw $* '<CR><C-W>T<C-W>':Nop
vquit :qa!

VtermVsshなどがなにやら激しいことになっています。

Vtermを例に見るとこれは実際に定義される関数が

function Vterm() {
  v :term $* '<CR><C-W>T<C-W>':Nop
}

となり、実際に実行される際はv関数内で

vim --servername $VIM_SERVERNAME \
    --remote-send "<C-W>:term {{Vtermの引数全て}}<CR><C-W>T<CR><C-W>:Nop{{Vtermの引数全て}}<CR>"

のように実行されます。これによって

  1. :term {{引数}} を実行
  2. <C-W>T で開いたバッファを新たなタブへ移動
  3. :Nop {{引数}} を実行

の順で処理を実行させることが可能です。
:Nopは余計なキー入力を抑制するためのVimコマンドで.vimrcなどで

function! Noperation()
endfunction
 
command! -nargs=* Nop call Noperation()

を定義しておいてください。

最後に

無理くり改造するのが楽しかっただけで他にもっと良いカスタマイズやプラグインなどがあるかもしれません。
みなさまも是非環境を魔改造し快適なCUIライフを

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?