fishのプラグインマネージャ比較

## はじめに
fish shellでのプラグイン管理にはこれまで[fisherman](https://github.com/fisherman/fisherman)を使っていたのですが，他のプラグインマネージャにはどんなものがあるんだろう？ と気になって調べてみたのでまとめます．

今回調べたのは以下の4つのプラグインマネージャです．

- `omf` ([oh-my-fish/oh-my-fish](https://github.com/oh-my-fish/oh-my-fish))
- `fisher` ([fisherman/fisherman](https://github.com/fisherman/fisherman))
- `fundle` ([tuvistavie/fundle](https://github.com/tuvistavie/fundle))
- `fresco` ([masa0x80/fresco](https://github.com/masa0x80/fresco))

`omf`は`Oh My Fish!`(`oh-my-fish`)というフレームワークに付属するもので，単なるプラグインマネージャではありませんが一緒に比較することにします．

## プラグインマネージャの比較
まず，プラグインマネージャの主要な機能についてまとめます．

|       |並行処理|関数の管理|補完の管理|キーバインド|初期設定ファイル|テーマとプラグインの区別|公式プラグイン|依存関係の記述|
|:-----:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|omf    |   |パスを通す|パスを通す|`fish_user_key_bindings`からsource|init.fish| ○ | ○ | bundle
|fisher | ○ |エイリアス作成|エイリアス作成|`fish_user_key_bindings`に追加|init.fish & conf.d配下| ○ | ○ | fishfile
|fundle |   |パスを通す|パスを通す|sourceで読む[^fundle_key]|init.fish||△| init.fish
|fresco |   |sourceで読む|sourceで読む|sourceで読む|init.fish & conf.d配下||| fishfile

[^fundle_key]: プラグインが`init.fish`を提供していない場合に，ルートディレクトリの`*.fish`をすべて読むという挙動によります．つまり，プラグインが`init.fish`と`key_bindings.fish`の両方を提供する場合はキーバインドは無視されます．

関数と補完の管理についてですが，fishのプラグインマネージャが関数(補完)を管理する方法としては

1. `fish_functions_path`(`fish_complete_path`)を変更してパスを通す
2. 標準でパスが通っている`~/.config/fish/functions(completions)`に関数(補完)のエイリアスを作成
3. プラグインマネージャーが`source`で読み込む(この場合はオートロード関数にできない)

があり，上の表ではそれぞれ`パスを通す`, `エイリアス作成`, `sourceで読む`と表記しています．

以下，各プラグインについて説明します．

## omf
fish shellのフレームワーク`oh-my-fish`が提供するプラグインマネージャです．
`oh-my-fish`は，インストール時点では`omf`とテスト関数の`fish-spec`しか入っていないので，`omf`でプラグインを追加していくことになります．

`omf install`でURLを指定すれば，`oh-my-fish`の公式プラグイン以外のものも管理できます．

```fish
omf install プラグイン名 # 公式プラグインのインストール
omf install https://github.com/ユーザ名/リポジトリ名 # 外部プラグインのインストール
```

特徴としては，`omf`ではプロンプト等を変更する「テーマ」と，その他のプラグイン(「パッケージ」と呼ばれる)を区別しており，`omf theme`でテーマの切り替えが簡単にできます．

便利な公式プラグインがたくさん存在するのが魅力ではありますが，`oh-my-fish`はfish shellのフレームワークであるため，そのあたりのルールはきちんと把握しておく必要があります．

たとえばfishのキーバインドは標準では`fish_user_key_bindings`関数に記載することになっていますが，`oh-my-fish`を導入すると**この関数はバックアップされた上で完全に上書き**されます．その後，ユーザー独自のキーバインドは`~/.confing/omf/key_bindings.fish`に書いていくことになります．
また，fishの設定は標準では`~/.config/fish/config.fish`に書くことになっていますが，`oh-my-fish`では`~/.confing/omf/init.fish`に書くことが推奨されています[^omf_config]．

[^omf_config]: 内容が完全に上書きされてしまう`fish_user_key_bindings`と異なり，`~/.config/fish/config.fish`は変更されず，そこに書いていた内容もこれまで通り反映されます．`~/.confing/omf/init.fish`に書くのは必須ではなく推奨，ということらしいです．

英文ですが最低限READMEは読んだ上での運用が必要です[^omf_man]．

[^omf_man]: 日本語READMEのプルリクも上がってるんですが，議論している間に本家READMEのバージョンが上がってしまってるようなので，やはり英語版READMEを読む必要があります．

## fisherman

fish shellのプラグインマネージャとしては，おそらく最もポピュラーなものです．
READMEに[日本語版](https://github.com/fisherman/fisherman/wiki/%E6%97%A5%E6%9C%AC%E8%AA%9E)が用意されているのが嬉しいところ．

公式プラグインが数多く提供されている他，oh-my-fishのプラグインも管理することができます．また，**Gistやローカルのディレクトリ**を管理することができるのも大きな特徴です．

```fish
fisher 公式プラグイン名
fisher omf/oh-my-fishのプラグイン名
fisher GitHubユーザー名/リポジトリ名
fisher GistのURL
fisher ローカルのディレクトリ
```

さらに，冒頭の表に示したプラグインマネージャの中では唯一，**並行処理によるプラグインインストール**を行います．

作者による日本語解説記事: [fish-shellによる並行処理の方法](http://qiita.com/jbucaran/items/9e41da125a9ed3182141)

ただ好みの分かれるところとしては，このプラグインは関数を管理するために**`~/.config/fish/functions`にエイリアスを貼る**，という方法を取ります．この場所はユーザーが自作の関数を置いておく場所でもあるため，この挙動を嫌がる方もいるようです．

また，キーバインドについては`fish_user_key_bindings`にプラグインの`key_bindings.fish`の内容を挿入する，という方法を取ります．

```fish:fish_user_key_bindings
function fish_user_key_bindings
	# ユーザーがもともと書いていた設定
    bind \cr 'begin; history | peco | read -l tmp; commandline $tmp; end'
    # 以下，fishermanによる挿入
    ### ghq ###
    bind \cg '__ghq_crtl_g'
    if bind -M insert >/dev/null ^/dev/null
        bind -M insert \cg '__ghq_crtl_g'
    end
    ### ghq ###
end
```

プラグインがviモード対応だったりすると結構な量のキーバインドが追加されるので，これも好みの分かれそうなところです．
プラグインが定義したキーバインドの全容が把握できるのと，不要だった場合はここでコメントアウトしておけば無効にできるのはメリットです．

また，`oh-my-fish`や後述の`fundle`では，プラグインが初期設定等を行う際には`init.fish`を使うことになっていますが，`fisherman`では`conf.d`ディレクトリ配下に複数の設定ファイルを配置しておくことを認めています．(`init.fish`があった場合は，それも管理してくれます)

## fundle
`fisherman`といい，何故かfishプラグインマネージャ作者には日本語話者が多いようで,作者本人による解説があります．

作者による日本語解説: [fish shell用のパッケージマネージャーを作りました](http://qiita.com/tuvistavie/items/053fa1ea56a05101a00e)

fishermanが関数のエイリアスを作るのと異なり，`fish_functions_path`を変更して関数にパスを通す方式のプラグインマネージャです．
[wiki](https://github.com/tuvistavie/fundle/wiki)に載ってるプラグインはまだ多くありませんが，管理方法が`omf`に類似しているため，`oh-my-fish`公式パッケージをはじめ，大抵のプラグインには対応できます．

このプラグインマネージャは依存関係の解決方法が他と少し違っていて,`init.fish`に`fundle plugin 依存するプラグイン名`と書き込むことになっています．
依存関係が拡張子`.fish`のスクリプトとして書かれてしまっているため，`fundle`用のプラグインを他のプラグインマネージャから利用すると，「fundleコマンドが見つからないよ！」というエラーになってしまいます．

現状，READMEに載っている方法で`fundle`を入れると補完設定がついて来ないので，`fundle`のお試しもかねて`~/.config/fish/config.fish`に以下のように書いておくとよいかもしれません[^fundle_comp]．

[^fundle_comp]: 他のプラグインマネージャから`fundle`をインストールすると補完が一緒に付いてくるので，それも一つの手ではあります．

```fish:config.fish
fundle plugin 'tuvistavie/fish-completion-helpers'
fundle plugin 'tuvistavie/fundle' --path 'completions'
fundle init
```

上記で使っているように`--path`オプションでリポジトリの特定のディレクトリだけ持ってこれるのは他のプラグインマネージャにないメリットです．

## fresco
作者による解説: [`fresco`：fish向けプラグインマネージャー](http://qiita.com/masa0x80/items/142bc668ea8e5084ce7c)

プラグインの管理に内部で`ghq`を利用するプラグインマネージャです．

関数も，補完も，キーバインドも，`init.fish`も`conf.d`配下の設定も，プロンプトも，全部起動時に`source`して読み込む，と割り切った実装になっています．

プラグインを大量に入れると起動が遅くなるという欠点はありますが，エイリアスも作成されませんし，`fish_user_key_bindings`が書き換えられることもありません．
**プラグインマネージャによって独自ルールがもたらされることがない**という点で，実は一番`fish`初心者にやさしいプラグインマネージャかもしれません．

`fish`はもともとが便利なシェルなので，大量のプラグインで武装することもないと思えば充分選択肢になります．
`fisherman`と同じく`fishfile`を読んで依存解決するので，プラグインが増えて起動時間が気になってきた場合は
```
cp ~/.config/fish/plugins.fish ~/.config/fish/fishfile
```
とするとすんなり`fisherman`に移行できるのも便利なポイントです．

注意すべき点としては，`config.fish`が読まれるより前に`ghq`が使用可能である必要があるので，`$GOPATH/bin`はグローバル変数`PATH`にではなく，ユニバーサル変数`fish_user_paths`に登録しておく必要があります．
コマンドラインで一度

```fish
set -U fish_user_paths $fish_user_path "$GOPATH/bin"
```

を実行しておけばOKです[^univ]．

[^univ]: これを`config.fish`に書いてしまうと，fishを起動するたびに変数が大きくなって行くので注意．

## その他のプラグインマネージャ
上記以外のプラグインマネージャをざっくり紹介．

### [fisherman/fin](https://github.com/fisherman/fin)
fishermanの作者によるミニマルなプラグインマネージャ．コードが300行に満たないながらも，並行処理が可能でプラグインの依存関係も解決してくれます．ただし，キーバインドは`fin`を実行したセッションの間のみ反映されます．


### [xtendo-org/chips](https://github.com/xtendo-org/chips)
並行処理が可能で，実装はHaskell.プラグイン管理にはYAMLを書きます．READMEを見る限り補完設定の管理は未対応の模様．

### [terlar/fish-plug](https://github.com/terlar/fish-plug)
fishermanと同じく，関数や補完設定のエイリアスを作成するタイプのプラグインマネージャです．

### [chewzerita/flub](https://github.com/chewzerita/flub)
`fish_greeting`でプラグインの読み込みを行います．その手があったかと意表を突くタイプのプラグインマネージャです．

## 終わりに
途中にも書きましたが，なぜか`fish`のプラグインマネージャ作者は日本語話者が多く，情報が手に入れやすいのは本当にありがたいところです．

色々調べましたが，私はこのまま`fisherman`を使い続けることにします．全部`source`方式の`fresco`もシンプルで好きだったんですが，使いたいプラグインの量が多かったので断念．

`fundle`は`fundle plugin プラグイン名`という記法が少し冗長かなと思ったのと，`fundle`用にプラグインを書いてしまうと(依存関係の解決のために`fundle`が必須なので)他のプラグインマネージャから利用しにくくなるのが難点ですかね...