vimのカラースキームをfishのカラースキームに変換するプラグイン

# TL;DR

記事タイトルそのままですが，vimのカラースキームをfishのカラースキームに変換するプラグインを作りました．

[ryotako/fish-vimcolor](https://github.com/ryotako/fish-vimcolor)

<img width=400px alt=vimcolor.mov.gif src=https://qiita-image-store.s3.amazonaws.com/0/124405/8ce870f5-0e24-fc0f-c495-11281e697223.gif>

# はじめに
今回こういったプラグインを作ろうと思ったきっかけは，愛用しているvimのカラースキーム[iceberg](http://cocopon.me/app/vim-iceberg/)の作者cocoponさんが作ったvimのカラースキームギャラリー「[colorswat.ch](http://colorswat.ch/vim)」でした．

このギャラリーそのものは先月あたりからあったのですが，最近新機能が追加されたと聞いてあらためてサイトを訪問[^colorswat]．
ひとしきりカラースキームを眺めて満足した後，こういうカラースキーム，シェルにもほしいなぁ... との思いに耐えられなくなって作ってしまいました．

fishでも`fish_config`で色設定できるのですが，バリエーションが少なくてちょっと物足りない感じでした[^vim]．

[^colorswat]: このカラースキームギャラリーは本当カッコイイのでぜひ一度訪問するのをおすすめしたいです．
[^vim]: ただ，これはむしろvimが凄すぎるんだと思います．歴史とかユーザ数とか.


# 使い方

まず好みのプラグインマネージャでプラグインをインストールします．とくにキーバインドも初期設定もないので，どのプラグインマネージャでも同じように可能なはずです．

```sh
# fishermanの場合
fisher ryotako/fish-vimcolor
```

基本的に`vimcolor vimのカラースキーム名`でそのカラースキームをfishに反映できます．
候補の取得に少し時間がかかりますが，コマンドの引数には手元のvimで利用可能なカラースキーム名が補完されます．
(`~/.vimrc`を読んだ後にvimのカラースキーム一覧を取得しているため，vimプラグインとしてインストールしたカラースキームも検出されます)

```
# vimにプラグインcocopon/iceberg.vimを導入済みとする

vimcolor iceberg
```

ただ，こうして反映されたカラースキームはfishを再起動するとリセットされてしまいます．設定を永続化したい場合は`-U(--universal)`オプションを付けてください．

```
vimcolor -U iceberg
```

こうすると設定のためにユニバーサル変数が使用されるようになり，次回以降の起動時にも色が反映されます．

また，利用可能なvimカラースキームを`-l(--list)`オプションで確認できます．

```
vimcolor --list
```

# vimとfishの色付けの対応関係

fishでは`fish_color_...`という名前の変数を使って色の設定ができます．vimでのシンタックスハイライトのグループと，fishの変数との関係は以下のようにしています．

参考:
[vimの日本語ドキュメント](http://vim-jp.org/vimdoc-ja/syntax.html)
[fishの英語ドキュメント](https://fishshell.com/docs/current/index.html)

fishの色設定|fishでの意味|vimのシンタックスor構文グループ|vimでの意味
---|---|---|---
fish_color_normal | デフォルトの色 | Normal | 通常のテキスト
fish_color_command | 実行可能なコマンド | Statement | 命令文
fish_color_quote | クォートされたブロック | String | 文字列定数
fish_color_redirection | 入出力リダイレクト | Directory | ディレクトリ名
fish_color_end | `;`や`&`のようなプロセス分割 | Delimiter | 注意が必要な文字
fish_color_error | エラー | Error | エラーなど、なんらかの誤った構造
fish_color_param | コマンドのパラメータ | Identifier | 変数名
fish_color_comment | コメント | Comment | コメント
fish_color_match | 対応する括弧 | MatchParen | カーソル下の文字に対応する括弧
fish_color_search_match | 選択している補完候補 | ~~Search~~ PmenuSel | ポップアップメニューの選択されている項目
fish_color_operator | `*`や`~`のような展開される演算子 | Operator | `sizeof`, `+`, `*`, その他
fish_color_escape | `\n`のようなエスケープされた文字 | SpecialChar |特殊な文字定数
fish_color_autosuggestion | オートサジェスト | Comment | コメント
fish_color_valid_path | 実在するパス | Underlined | 目立つ文章 
fish_color_history_current | `dirh`コマンド出力中の現在のディレクトリ | Directory | ディレクトリ 
fish_color_selection | viモードでビジュアル選択された範囲 | Visual |  ビジュアル選択された範囲
fish_pager_color_prefix | 補完候補の一致部分 | Title | ":set all"、":autocmd" などによる出力のタイトル
fish_pager_color_completion | 補完候補の色 | Pmenu | ポップアップメニューの通常の項目
fish_pager_color_description | 補完候補の説明の色 | SpecialComment | コメント内の特記事項
fish_pager_color_progress | 補完候補が多い時の`...and X more lines`の色 | MoreMsg | スクリーンがメッセージで埋め尽くされた時に表示される`-- More --`の色

本当は`fish_color_user`とか，`fish_color_`で始まる変数はもっとあります．
ただ，これはデフォルトのプロンプトを使用している場合にしか意味が無いのと，ユーザ名って構文要素でいうと何に相当するのか？ が決められなかったので設定していません．

# メリットとデメリット
このプラグインのメリットは手軽に，豊富なカラースキームを試せるところだと思うのですが，デメリット(というか未熟な部分)も結構あります．
まとめると以下のようになります．

## メリット
- vimの豊富なカラースキームが利用可能.
- 環境設定を開かずにコマンド一発で気軽に色変更できる．
- シェルが色付けするため，`ターミナル.app`や`iTerm.app`といったソフトごとに設定をしなくてもよい．

## デメリット
- ターミナル全体の背景色は設定不可能．
- 実行時にちらっと`vim`の画面が描画されることがある[^silent]．
- `set_color red`などで指定される`red`が実際には何色なのか？ は変数`fish_color_...`で制御できないためターミナルの環境設定が必要．
- ~~fishが解釈できない色名がある(`DarkGrey`とか)．~~ → 対応しました
- fishのシンタックスグループによって，指定不可能な設定がある．たとえば`fish_color_search_match`は`--background`オプションしか受け付けてくれず，前景色や太字指定ができない．
- fishのシンタックスグループによって，背景色を指定したはずなのに太字にされる等の謎の挙動がある．

あと，これ個人利用なら問題ないと思いますけど，変換したカラースキームを公開したりするする場合には元のカラースキームのライセンスを確認する必要があるかもです．

[^silent]: これなんとかしたいと思ってvimをサイレントモードで起動(`vim -es`)してみたりしたのですが，どうせ描画されないからなのか，サイレントモードだとカラースキームの変更ができないっぽいのですよね...

# おわりに
fishはもともとがカラフルなシェルですが，vimの力を借りて色々なカラースキームが使えるようになりました．
ターミナルでの作業がもっと楽しくなりそうですね！

# 追記
補完時の選択肢の色設定(`fish_pager_color_...`)に対応しました．また，それにともなって選択中の候補の色付けをvimの`Search`から`PmenuSel`に変更しました．