Vim の下着で gVim を高速起動する (起動するとは言ってない

この記事は Vim (その2) Advent Calendar 2016 の17日目の記事です。

# Vim の起動が遅い?

Vim の起動速度が云々という話題が時折あり、自分もなんとなく気になっていました。
闇のプラグインマネージャである [dein.vim](https://github.com/Shougo/dein.vim) を試したりもしました。
しかし、聖なる存在である私 [anekos](http://profile.hatena.ne.jp/nokturnalmortum/) とは相性が悪いようで、奇妙な動きに翻弄されるばかり。
不具合報告したくとも、<strike>奇怪</strike>複雑な動作のため、超面倒くさい!
あきらめた!


# 起動時間はあきらめる

実際のところ、起動速度が遅いというのは、本質的な問題ではないはず。
Vim を使いたいと思ってから、実際に使えるまでの時間こそが問題です。

それに、起動時間を短くするために色々考えるのも面倒。


# 起動しなければ 0 秒?

そういうわけで、起動するから時間がかかるので、あらかじめ起動しておくという方針にしました。
つまり、gVim をあらかじめ何個かストック(起動)しておいて、そこから引っ張り出すだけにするのです。


# panty コマンド書いた

そしてできたのが `panty` というコマンドです。
はじめは、シェルスクリプトだったのですが、最近 Rust で書き直しました。

[anekos/panty: Super fast gVim summoner](https://github.com/anekos/panty)

Linux の X 用なので、Mac の人は [こちら](https://wiki.archlinuxjp.org/index.php/MacBook) を参考にすると良いでしょう。

## インストル方法

インストール(ビルド)には、`rust` のパッケージマネージャの `cargo` が必要です。
(Arch Linux であれば、公式リポジトリにどちらもあるので、サクっとインストールできます。)

```
$ cargo install panty
$ ~/.cargo/bin/panty -h
```

これで、`~/.cargo/bin/panty` にコマンドができます。
適当にパスを通すなりしましょう。


## 使用方法

まずは、gVim をストックするためのサーバ的なものを起動します。
↓の例では、`--stocks 3` の数だけ gVim をストックしておき、`--watch` で指定されたファイルが更新されると、ストックを再起動して更新します。
これは終了しないので、そのまま放置しておきます。

```
$ panty collector --stocks 3 --watch ~/.vimrc --watch ~/.gvimrc
```

あとは、gVim を起動したいときに

```
$ panty summon ~/.vimrc
```

のようにすると、裏で起動していた gVim がシャキっと出現し、`~/.vimrc` を開きます。
ショートカットなどで起動できるようにしておくと良いでしょう。


# pros/cons

## 良いとこ

- 高速起動 (もどき)
- .vimrc の書き方などを工夫しなくても良い
- Rust で遊べた

## 悪いとこ

- .vimrc を書き換えた場合、起動が遅れる (上記の`--watch`オプションを使う場合)


個人的には、vim 関係をいじる時は単純に二つ vim を起動してテストしているので、あまり問題になりません。


# 実際の速度

実際、どれほどの速度か簡単に計測してみました。
うちの環境では、`<A-S-g>` で `panty summon` が呼ばれるので、これを押した一定時間後に、`a` を押すようにします。
これで、インサートモードに入っていれば、その一定時間後には起動が完了しているという寸法です。

実際のテストは以下のようにしました。
`$MSEC` の部分が問題の時間です。

```
$ MSEC=0.5
$ sleep 1; xdotool key --delay 0 alt+shift+g ; sleep "$MSEC"; xdotool key --delay 0 a
```

正確な計測とはいいづらいですが、おおよそ `$MSEC` が `0.02` もあればちゃんと起動完了し、インサートモードへ入れているようです。
ほぼウィンドウを表示しているだけなので、もっと速くても良い気もしますが、これ以上速くても意味はないでしょう。
実際に手で入力しても、即インサートモードに入れる感じです。
通常だと、0.5 秒くらいかかっていたようなので、かなり速くなった印象です。

そういうわけで目的は無事達成できたようです!

<!--
## GUI の起動速度

vim には起動速度計測機能があるようなので、それを使って **gVim** を調べてみました。

```
$ gvim -u NORC --noplugin --startuptime vime.log +q
$ cat vime.log
times in msec
 clock   self+sourced   self:  sourced script
 clock   elapsed:              other lines

000.008  000.008: --- VIM STARTING ---
000.121  000.113: Allocated generic buffers
000.245  000.124: locale set
000.266  000.021: GUI prepared
000.267  000.001: clipboard setup
000.273  000.006: window checked
000.757  000.484: inits 1
000.765  000.008: parsing arguments
000.767  000.002: expanding arguments
000.782  000.015: shell init
001.103  000.321: Termcap init
001.165  000.062: inits 2
001.366  000.201: init highlight
001.368  000.002: sourcing vimrc file(s)
001.377  000.009: inits 3
010.857  000.068  000.068: sourcing /usr/share/vim/vim80/autoload/paste.vim
028.229  018.473  018.405: sourcing $VIMRUNTIME/menu.vim
209.271  189.421: starting GUI
263.287  054.016: GUI delay
264.054  000.767: register server name
264.057  000.003: setting raw mode
264.058  000.001: start termcap
264.098  000.040: clearing screen
264.447  000.349: opening buffers
264.449  000.002: BufEnter autocommands
264.452  000.003: editing files in windows
```

`stating GUI` と `GUI delay` で時間がかかっているようですね。
-->


# TODO

最近シェルスクリプトから移植をしはじめたので、ちょっと足りてないとこあります。

- 起動する gVim のパス指定
- 他のオプションもわたせるようにする

など。

使いたい人がいて欲しい機能とかあれば、Issue 登録するか Twitter で言ってください。

(ちなみに、過去のコミットにシェルスクリプトも入ってたりしますが、こちらは自分の環境に強く依存しているので参考程度にしかならないと思います)

# オマケ

## svim

似たものとして、`singleton.vim` というのがありますが、`panty` と併用するのに良いものとして、[anekos/svim: gVim singleton or gVim window selector on current workspace](https://github.com/anekos/svim)  というのがあります。
画面上に見えている gVim のどれかにファイルを送りこむというものです。


## XMonad の設定

[xmonad](http://xmonad.org/) は、アイコン状態でのアプリの起動に対応していないっぽいので、ManageHook を以下のようにすると良いと思います。

```
import XMonad hiding (doShift)
import qualified XMonad.StackSet as SS
import XMonad.Util.XUtils (hideWindow)

myManageHook :: ManageHook -> ManageHook
myManageHook = composeAll
    [ ...
      , role      =? "STOCKING"           --> doHide ]

doHide :: ManageHook
doHide = ask >>= \w -> liftX (hideWindow w) >> doF (SS.delete w)

role :: Query String
role = stringProperty "WM_WINDOW_ROLE"
```


## Vim の下着

> gVim をストックしておく → Stock → Stocking → ストッキング → [ストッキングといえばパンティー](https://ja.wikipedia.org/wiki/%E3%83%91%E3%83%B3%E3%83%86%E3%82%A3%26%E3%82%B9%E3%83%88%E3%83%83%E3%82%AD%E3%83%B3%E3%82%B0with%E3%82%AC%E3%83%BC%E3%82%BF%E3%83%BC%E3%83%99%E3%83%AB%E3%83%88)らしい

こういう理論で、panty という名前になりました。