MSYS2でfishを使う

msys2 には [fish shell](http://fishshell.com/) のパッケージが用意されています。
bash からプロンプトで `fish --login` するだけなら簡単ですが、起動時のログインシェルとして使用するためにはいろいろ注意点がありましたのでまとめます。

# 1. fish のインストール

何はともあれ、pacman を利用して `fish` をインストールします。
fishは内部で暗黙的に`man(nroff)` と `bc` を利用するので、これもあわせてインストールしておきます。

```
pacman -S fish man bc
```

# 2. `/usr/etc/fish/config.fish` の編集

fish をログインシェルとして利用する場合を考えると、bash であれば `/etc/profile` で設定されているはずの `/usr/bin` 等のパスが設定されていないため、msys2_shell.bat 等で単純に bash の部分を fish に書き換えて起動しようとすると大量のエラーを見るはめになります。

まずは、 `/etc/profile` での指定に相当する設定を `/usr/etc/fish/config.fish` に記述します。
同ファイルの、 `if status --is-login` (ログインシェルとして起動)の条件内に以下のコードを追加します。

Windows の既存のパスを引き継ぎたくない場合は、1行目末尾の `$PATH` は抜いておいてもよいです(そのほうがパスが混じらなくてよいような気もする)。

```
	set PATH /usr/local/bin /usr/bin /bin $PATH
	set MANPATH /usr/local/man /usr/share/fish/man /usr/share/man /usr/man /share/man $MANPATH
	set -gx INFOPATH /usr/local/info /usr/share/info /usr/info /share/info $INFOPATH
	if test -n $MSYSTEM
		switch $MSYSTEM
			case MINGW32
				set MINGW_MOUNT_POINT /mingw32
				set -gx PATH $MINGW_MOUNT_POINT/bin $MSYS2_PATH $PATH
				set -gx PKG_CONFIG_PATH $MINGW_MOUNT_POINT/lib/pkgconfig $MINGW_MOUNT_POINT/share/pkgconfig
				set ACLOCAL_PATH $MINGW_MOUNT_POINT/share/aclocal /usr/share/aclocal
				set -gx MANPATH $MINGW_MOUNT_POINT/share/man $MANPATH
			case MINGW64
				set MINGW_MOUNT_POINT /mingw64
				set -gx PATH $MINGW_MOUNT_POINT/bin $MSYS2_PATH $PATH
				set -gx PKG_CONFIG_PATH $MINGW_MOUNT_POINT/lib/pkgconfig $MINGW_MOUNT_POINT/share/pkgconfig
				set ACLOCAL_PATH $MINGW_MOUNT_POINT/share/aclocal /usr/share/aclocal
				set -gx MANPATH $MINGW_MOUNT_POINT/share/man $MANPATH
			case MSYS
				set -gx PATH $MSYS2_PATH /opt/bin:$PATH
				set -gx PKG_CONFIG_PATH /usr/lib/pkgconfig /usr/share/pkgconfig /lib/pkgconfig
				set -gx MANPATH $MANPATH
			case '*'
				set -gx PATH $MSYS2_PATH $PATH
				set -gx MANPATH $MANPATH
		end
	end

	set -gx SYSCONFDIR /etc

	set ORIGINAL_TMP $TMP
	set ORIGINAL_TEMP $TEMP
	set -e TMP
	set -e TEMP
	set -gx tmp (cygpath -w $ORIGINAL_TMP 2> /dev/null)
	set -gx temp (cygpath -w $ORIGINAL_TEMP 2> /dev/null)
	set -gx TMP /tmp
	set -gx TEMP /tmp

	set p "/proc/registry/HKEY_CURRENT_USER/Software/Microsoft/Windows NT/CurrentVersion/Windows/Device"
	if test -e $p
		read PRINTER < $p
		set -gx PRINTER (echo $PRINTER | sed -e 's/,.*$//g')
	end
	set -e p

	if test -n $ACLOCAL_PATH
		set -gx ACLOCAL_PATH $ACLOCAL_PATH
	end

	set -gx LC_COLLATE C
	for postinst in /etc/post-install/*.post
		if test -e $postinst
			sh -c $postinst
		end
	end
```

## 2-2 パスに `(x86)` が含まれているとき、`<TAB>` 補完に失敗する件への対応

[complete.cpp does not parse PATH directories with parenthesis correctly. #952 fish-shell/fish-shell](https://github.com/fish-shell/fish-shell/issues/952#issuecomment-27499216)

64bit Windows の場合、`$PATH`に`(x86)`が含まれています。
この環境で msys2 上の fish のプロンプトで`<TAB>`キーでコマンドの補完をした時、 fishは`$PATH`中の `(x86)` をコマンド実行の置換のための `(...)` の構文と解釈して、`x86` というコマンドを実行しようとしてしまい、結果 `<TAB>` 補完中にエラーが出力される、という現象が発生します。。

そこで、上記 `/usr/etc/fish/config.fish` に、以下の function を定義します。

```
	function x86
		echo '(x86)'
	end
	function X86
		echo '(X86)'
	end
```

(x86) がコマンドとして解釈された場合に "(x86)" を返すという、たいへんバカバカしい Workaround ですが、ちゃんと動きます。

# 3. `c:/msys64/msys2_shell.bat` を編集

ここまでやったら、スタートメニューの`MSYS2 shell.bat`から fish が起動するように変更します。

```batchfile
start %WD%mintty -i /msys2.ico /usr/bin/bash --login %*
```

のところを

```batchfile
SET XDG_RUNTIME_DIR=/tmp/fish.%USERNAME%
start %WD%mintty -i /msys2.ico /usr/bin/fish --login %*
```

に変更します。

`XDG_RUNTIME_DIR` を変更しているのは、msys2 や cygwin ではこの変数がシェル起動時に自動的に設定できないようで、手動で指定しない場合に、エラーとなってしまうためです。
(https://github.com/fish-shell/fish-shell/issues/1887#issuecomment-70234859)

# 4. ConEmu からの起動

さらにおまけで、ConEmu でも利用したい場合は、以下のような Task を追加して、以下のようなコマンドを指定します。

```
C:\msys64\usr\bin\sh.exe -c 'LANG=C.UTF-8 MSYSTEM=MSYS XDG_RUNTIME_DIR=/tmp/fish.$USERNAME exec /usr/bin/fish --login' -new_console:C:"\msys64\msys2.ico" -new_console:d:"%USERPROFILE%"
```

`$LANG` が Windows の指定と異なる場合もあるので、その場合は指定しておきます。
特に、Windowsでの環境変数 `$LANG` に文字コードを含めないロケールを指定している場合、コマンドプロンプト等に記号を出すような場合(oh-my-fishとか入れたいですよね？)にエラーが表示されることがあります。

ただ、ConEmu上でのfishの挙動はちょっと怪しい感じで、fish自体が突然落ちたり、右プロンプトを指定していると文字入力の度に改行されてしまったりするため、あまりオススメしないです。素直にmintty上で使うのがよさげ。