はじめに

fish shellでのプラグイン管理にはこれまでfishermanを使っていたのですが,他のプラグインマネージャにはどんなものがあるんだろう? と気になって調べてみたのでまとめます.

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

omfOh 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で読む1 init.fish init.fish
fresco sourceで読む sourceで読む sourceで読む init.fish & conf.d配下 fishfile

関数と補完の管理についてですが,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の公式プラグイン以外のものも管理できます.

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に書くことが推奨されています2

英文ですが最低限READMEは読んだ上での運用が必要です3

fisherman

fish shellのプラグインマネージャとしては,おそらく最もポピュラーなものです.
READMEに日本語版が用意されているのが嬉しいところ.

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

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

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

作者による日本語解説記事: fish-shellによる並行処理の方法

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

また,キーバインドについてはfish_user_key_bindingsにプラグインのkey_bindings.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用のパッケージマネージャーを作りました

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

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

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

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

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

fresco

作者による解説: fresco:fish向けプラグインマネージャー

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

関数も,補完も,キーバインドも,init.fishconf.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に登録しておく必要があります.
コマンドラインで一度

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

を実行しておけばOKです5

その他のプラグインマネージャ

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

fisherman/fin

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

xtendo-org/chips

並行処理が可能で,実装はHaskell.プラグイン管理にはYAMLを書きます.READMEを見る限り補完設定の管理は未対応の模様.

terlar/fish-plug

fishermanと同じく,関数や補完設定のエイリアスを作成するタイプのプラグインマネージャです.

chewzerita/flub

fish_greetingでプラグインの読み込みを行います.その手があったかと意表を突くタイプのプラグインマネージャです.

終わりに

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

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

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


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

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

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

  4. 他のプラグインマネージャからfundleをインストールすると補完が一緒に付いてくるので,それも一つの手ではあります. 

  5. これをconfig.fishに書いてしまうと,fishを起動するたびに変数が大きくなって行くので注意.