choosewin.vim をつくりました

この記事はVim Advent Calendar 2013 44回目(不吉な..)の記事です。

新しいプラグイン vim-choosewin を作りました。
最初に作ったのは去年(2013年)の12月なのですが、正月頃、manga-osyo さんに
色々とアイデアを貰い、発展し、けっこう大げさなプラグインになりましたので紹介します。


■ これは何をするものか?
以下の GIF アニメを見てください。

ウィンドウに表示されるラベルを入力することで、目的のウィンドウに一発で移動できます。


■ 作った背景
tmux というターミナルマルチプレクサ(一つのターミナルで、沢山のウィンドウを開いたりするソフト)
があります。 Mac とか、Linux の人は使っている人も多いでしょう。
tmux には display-pane というコマンドがあり、数字キーを押すことで、飛びたいウィンドウに一足飛びに移動できます。


※ tmux の display-pane 機能: こんな画面で数字キーを押すと数字の Window にフォーカスが移る。


今回作成した choosewin は tmux のこの機能に着想を得たものです。
大きな解像度の、広い広いディスプレイを使っている人は、沢山ウィンドウを開いているでしょう。
沢山開いていると、一番右端のウィンドウから、一番左端のウィンドウまで移動するのにとても苦労するでしょう。
私はウィンドウの移動を CTRL キー jkhl と組み合わせて移動する様にしていますが、
一番右下、一番左上の移動には、C-h C-h C-h C-k C-k とかやらにゃならん。
そうなるとコントロールの押しすぎで、小指が痛むでしょう。
小指が痛むと悲しいでしょう。

ということで、Choosewin はこの問題を解決すべく作りました。



■ インストールと使い方
NeoBundle 等でインストール後 (choosewin) をマッピングして下さい。
以下の例では、'-' で choosewin を呼び出すようにマッピングしてます。

nmap  -  <Plug>(choosewin)


ウィンドウ選択は以下のような流れになります。

  1. '-' で choosewin を呼び出す。
  2. 各ウィンドウのステータスバー又は、画面の真ん中(オーバーレイ機能有効時:後述)にラベルが出る。
  3. 移動したいウィンドウのラベルを入力
  4. 選択したウィンドウに着地する。

同様にタブにもラベルが出るので、ラベルを入力することで別タブのウィンドウにも移動できます。
タブ間の移動はラベルを入力して移動する以外に、以下のキー操作でも行えます。

キー アクション 何するか?
0 tab_first 最初(一番左)のタブへ
[ tab_prev 前のタブ
] tab_next 次のタブ
$ tab_last 最後(一番右)のタブへ
; win_land カレントウィンドウに着地
win_land カレントウィンドウに着地
マッピングを消すときに使う

■ オーバーレイ機能
choosewin のデフォルト設定では、ウィンドウラベルはステータスバーに出るのみです。

大きな画面ですと、目線が移動して不便でしょう。
画面の広大さに比して、ステータスラインは細すぎてほぼ見えないでしょう。
tmux は各ウィンドウの真ん中に大きな文字でラベルが出るので、やっぱりあんまり便利じゃないかも、と思ったでしょう。

そんな人は勇気を出して以下の機能を有効にしてみてください。

" オーバーレイ機能を有効にする。
let g:choosewin_overlay_enable = 1

" オーバーレイ時、マルチバイト文字を含むバッファで、ラベル文字が崩れるのを防ぐ
let g:choosewin_overlay_clear_multibyte = 1

これで各ウィンドウの真ん中にラベル文字が出るようになります。

かなり tmux のオリジナルの機能に近づきました。
目線も動かないし、素晴らしい。

しかし先ほど「勇気を出して」機能を有効にする、と書いたように、この機能を実現するために、結構無茶なことをやっています。

Vim は画面にフォントをオーバーラップして表示する機能をサポートしていません。
そのため、matchadd() というハイライト機能で、1バイトずつハイライトして、ドット文字として、ラベルを表現しています。

タブ文字や、マルチバイト文字があると、1バイトずつのハイライトが出来ないのでラベル表示前にこれらの文字を空白スペースに置き換えたり、ファイルの末尾だと、何も文字がないので、行を追加したり、という大げさな事をやっています。

単なるウィンドウ移動にこれは大げさだ、とか、ハイライトが遅い、とか、あるいはまだ多くの人がつかっていないので、破壊的エラーが起こらないとも限らない、とかでデフォルトで無効にしていますが、
私自身の印象としては結構イケそうな気がするので、どんどん使ってみていただきたいです。




■ 最後に、私の設定
私は、オーバーレイをメインで使用し、ステータスラインのリプレイスも、タブラインのリプレイスも無効にしています。
色は、tmux の雰囲気に合わせています。

" '-' で呼び出し
nmap  -  <Plug>(choosewin)

" オーバーレイを使う
let g:choosewin_overlay_enable = 1

" マルチバイトバッファでオーバーレイフォントを崩さないように
let g:choosewin_overlay_clear_multibyte = 1

" tmux の色に雰囲気を合わせる。
let g:choosewin_color_overlay = {
      \ 'gui': ['DodgerBlue3', 'DodgerBlue3' ],
      \ 'cterm': [ 25, 25 ]
      \ }
let g:choosewin_color_overlay_current = {
      \ 'gui': ['firebrick1', 'firebrick1' ],
      \ 'cterm': [ 124, 124 ]
      \ }

let g:choosewin_blink_on_land      = 0 " 頼むから着地時にカーソル点滅をさせないでくれ!
let g:choosewin_statusline_replace = 0 " どうかステータスラインリプレイスしないで下さい!
let g:choosewin_tabline_replace    = 0 " どうかタブラインもリプレイスしないでいただきたい!