fish shellでrbenvを使う

fish shellでrbenvを使うための手順と、ここに至るまでに得られた知見について書きました。


## 環境

- Ubuntu 16.04
- [fish](https://fishshell.com/) 2.7.0
- [fisherman](https://fisherman.github.io/) 2.13.2 - fishのプラグインマネージャ
  - [rbenv](https://github.com/fisherman/rbenv)プラグイン - rbenvに関する細々した設定を裏でやってくれる
- [rbenv](https://github.com/rbenv/rbenv) 1.1.1-6-g2d7cefe

rbenv本体と区別するため、fishermanプラグインの方は「rbenvプラグイン」と記載します。

## 導入の流れ

### rbenvを入れる

```
$ git clone https://github.com/rbenv/rbenv.git ~/.rbenv
```

通常はこのあとに環境変数を足したりしますが、rbenvプラグインがそのあたりをやってくれるので、これだけでOKです。[^1]


### fishを入れる

fishのリポジトリを追加してaptでインストールします。

```
$ sudo apt-add-repository ppa:fish-shell/release-2
$ sudo apt-get update
$ sudo apt-get install fish
```

fishの[公式ページ](https://fishshell.com/)に各環境用の導入方法が書いてあるので、ubuntu以外はそちらを参照してください。


### fishermanを入れる

プラグインマネージャのfishermanを入れます。
fishermanの実体はfishスクリプト1個だけです。

```
$ curl -Lo ~/.config/fish/functions/fisher.fish --create-dirs https://git.io/fisher
```

### rbenvプラグインを入れる

fishermanでrbenvプラグインをインストールします。
``fisher install rbenv``が本来の書き方ですが、installは省略できます。

```
$ fish
~> fisher rbenv
```

``~>``となっている部分はfish内での操作です。
rbenvプラグインのインストール中に下記のようなエラーが出ると思います。

```
rbenv: command not found. See https://github.com/rbenv/rbenv
The program 'rbenv' is currently not installed. You can install it by typing:
sudo apt install rbenv
~/.config/fish/functions/rbenv.fish (line 8):
    command rbenv "$command" $argv
            ^
in function “rbenv”
        called on line 1 of file ~/.config/fish/completions/rbenv.fish
        with parameter list “commands”

in command substitution
        called on line -1 of file ~/.config/fish/completions/rbenv.fish

from sourcing file ~/.config/fish/completions/rbenv.fish
        called on line 839 of file ~/.config/fish/functions/fisher.fish

in function “__fisher_plugin_enable”
        called on line 445 of file ~/.config/fish/functions/fisher.fish
        with parameter list “/home/ubuntu/.config/fisherman/rbenv”

in function “__fisher_install”
        called on line 274 of file ~/.config/fish/functions/fisher.fish
        with parameter list “rbenv”

in function “fisher”
        called on standard input
        with parameter list “rbenv”
```

rbenvプラグインがrbenvの実体を見つけられないのでエラーになっています。
次項の設定ファイルを追加すれば解消します。


### conf.dに設定ファイルを追加

``~/.config/fish/conf.d/``に設定ファイルを1つ追加します。理由は後述。

``` ~/.config/fish/conf.d/000-env.fish
set -x PATH $HOME/.rbenv/bin $PATH
```

rbenvのインストール先を環境変数PATHに追加しています。
これで動くようになったはず。



## おまけ

### fishの挙動

fishのお作法では、``.bashrc``等の代わりに``config.fish``というファイルを使います。個人用の設定はここに書く、というルールです。

本来はrbenvのパスも``config.fish``に書くべきなのですが、fishが設定ファイルを読み込む順番の兼ね合いで不都合が出てしまいます。
以下は公式ドキュメントでの記載。

> Configuration files are evaluated in the following order:
> 
> - Configuration shipped with fish, which should not be edited, in $__fish_datadir/config.fish (usually /usr/share/fish/config.fish).
> - System-wide configuration files, where administrators can include initialization that should be run for all users on the system - similar to /etc/profile for POSIX-style shells - in $__fish_sysconfdir (usually /etc/fish/config.fish);
> - Configuration snippets in files ending in .fish, in the directories:
>   - $XDG_CONFIG_HOME/fish/conf.d (by default, ~/.config/fish/conf.d/)
>   - $__fish_sysconfdir/conf.d (by default, /etc/fish/conf.d)
>   - /usr/share/fish/vendor_conf.d (set at compile time; by default, $__fish_datadir/conf.d)
> - User initialization, usually in ~/.config/fish/config.fish (controlled by the XDG_CONFIG_HOME environment variable).
>
> [fish shell documentation - 2.6.0](https://fishshell.com/docs/current/index.html#initialization)

簡単にまとめるとこんな感じで、上から順に読み込まれます。

1. fish組み込みの設定ファイル (編集するべきじゃないファイル)
2. システム全体向け設定 /etc/fish/config.fishなど
3. 個人向けスニペット ~/.config/fish/conf.d/
4. 個人向け設定 ~/.config/fish/config.fish

### 000-env.fishを入れる理由

rbenvプラグインは3つ目のconf.d/にインストールされるのですが、上記の通りconf.d/の中はconfig.fishよりも先に読み込まれます。

rbenvプラグインが動くのに環境変数PATHの設定が必要だけど、環境変数PATHを書くべきconfig.fishはrbenvプラグインよりも後に読み込まれるという悲劇!!

過去にこの仕様に関するIssueも上がっていたみたいです。
[Document conf.d / config.fish sourcing order #3099](https://github.com/fish-shell/fish-shell/issues/3099)

結局、conf.d/の中で一番早く実行されるような名前のファイル(000-env.fish)を作り、conf.d/内のスニペットが依存している環境変数等は全部そこに書いてしまおう、という対応が定番になったようです。


[^1]: ruby-buildとかコンパイラの手順は、今回の本筋から外れるので省いています。