秋の dotfiles 大掃除【シェル編】- fish 🐟

macOS Catalina の標準のシェルは `zsh` ですが、今回はシンタックスハイライトやコマンド履歴の補完などが優秀な **[fish](https://fishshell.com)** を紹介します:fish:

![fish_shell-demo](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227668/c2ca7696-0de9-bcf2-0028-7c22ed9a376d.png)

fish には次のような特徴があります。

- コマンド履歴や completions から自動でコマンドを補完する
- 24bit true color に対応している
- シンタックスハイライトがシンプルで見やすい
- カラーやプロンプト、キーバインドなどをブラウザ上で設定できる
- POSIX（シェルスクリプトの仕様）とは非互換

POSIX非互換なので fish 用のスクリプトを作る際はややクセがありますが、従来のシェルスクリプトよりも簡単でわかりやすいものがかけると思います。

# 環境

<div>
  <img src="https://img.shields.io/badge/macOS Catalina-19.15.7-999999.svg?logo=apple&style=flat-square">
  <img src="https://img.shields.io/badge/fish-3.1.2-BED4EB.svg?&style=flat-square">
</div>

| macOS Catalina | 19.15.7   |
|:---------------|:----------|
| __fish__       | __3.1.2__ |

# 1. インストール

[Homebrew](https://brew.sh/) でサクッとインストールできます。

```bash
brew install fish
```

`etc/shells` に fish のパスを通して、 `chsh` コマンドでデフォルトシェルを fish に変更します。

```bash
sudo vi /etc/shells
# 末尾に /usr/local/bin/fish を追加

chsh -s /usr/local/bin/fish
```

エラーが出る場合は、`etc/shells` に `/usr/local/bin/fish` が正しく追加されていることを確認してください。
ちなみに私の場合は、デフォルトのシェルを変更したくないので `Alacritty（ターミナルアプリ）` の設定で fish を起動するように変更しています。

# 2. 設定

fish の設定ファイルは `~/.config/fish/` ディレクトリにあります。
fish に PATH を通したりツールの初期化（init）、エイリアスを登録したりする設定は `~/.config/fish/config.fish` に記述し、 コマンドの補完は `~/.config/fish/completions/` ディレクトリに追加することで fish 起動時に自動で読み込まれます。同様に、 fish 起動時に読み込ませたいスクリプトは `~/.config/fish/functions/` ディレクトリに `*.fish` の形式で配置することで自動的に読み込まれます。

```bash
~/.config/fish
├── completions                     # 各種コマンドの補完ファイル
│  ├── docker-compose.fish
│  ├── docker.fish
│  ├── git.fish
│  └── rustup.fish
├── config.fish                     # fish の基本設定ファイル
├── fish_prompt.fish                # プロンプトをブラウザで設定した際に作成されるファイル
└── functions
   ├── fish_user_key_bindings.fish  # fish のキーバインドを設定するファイル（デフォルト）
   ├── fzf_key_bindings.fish        # fzf インストール時に自動で生成されたファイル
   └── mkcd.fish                    # mkdir と cd を行うスクリプト
```

## 2.1 PATHの通し方

fish の PATH 設定は、従来どおり `$PATH` に追加する方法と fish 独自の `$fish_user_paths` というユニバーサル変数に追加する方法があります。

### 2.1.1 `$PATH` に追加する

`/usr/local/bin` を `$PATH` に追加するには `config.fish` に以下の文を追加します。

```shell:~/.config/fish/config.fish
set PATH /usr/local/bin $PATH
```

ただし、この方法だとfish セッションを起動するごとに `$PATH` に追加されるので PATH が重複する問題があります。

### 2.1.2 `$fish_user_paths` に追加する

PATH 重複問題を解決するために、 fish にはすべてのセッションで共通の PATHを設定できる `$fish_user_paths` というユニバーサル変数があるので、特別な理由がない場合はこちらに設定するのが良いでしょう。

`/usr/local/bin` を `$fish_user_paths` に追加するには次のコマンドを実行してください。

```shell
set -U fish_user_paths /usr/local/bin $fish_user_paths
```

<font color="OrangeRed">**ただし、このコマンドを `~/.config/fish/config.fish` に記述しないようにしてください！**</font> `~/.config/fish/config.fish` に記述してしまうと fish を起動するたびに `$fish_user_paths` に追加されてしまうので起動時間がとても遅くなってしまいます。

どうしても `~/.config/fish/config.fish` に PATH を設定したい場合もあると思うので、その場合は次のようにすると良いでしょう。

```shell:~/.config/fish/config.fish
set -g fish_user_paths /usr/local/bin $fish_user_paths
```

## 2.2 コマンド補完

fish は標準のコマンド（`ls` や `cat` ）に対してコマンドの補完はできますが、`docker` や `hub` などのコマンドの補完には対応できていません。そこで、 [こちら](https://github.com/fish-shell/fish-shell/tree/master/share/completions) から `docker.fish` などのファイルをダウンロードして `~/.config/fish/completions/` 配下に追加することで fish 起動時に自動でファイルを読み込み、コマンドの補完をしてくれます。

---
**参考サイト**
> [fish shellのPATH設定 - Qiita](https://qiita.com/ledsun/items/8ca1a450b21c8ebc9670)