Windows & WSL Linux & Hyper & Fish & PhraseExpress

# 目的

　WSL(Windows Subsystem for Linux)の登場により、開発環境としてのWindowsの利便性は格段に向上しつつある。

　今回は、WSL上のLinuxとWindowsを相互に行き来しながら開発するために、細かい環境を整えたので、些末な内容だが共有する。

# WSLインストール

　以下の記事を参照して導入する。
　[Windows 10でLinuxプログラムを利用可能にするWSL（Windows Subsystem for Linux）をインストールする（バージョン1803対応版）](http://www.atmarkit.co.jp/ait/articles/1608/08/news039.html)

## Hyperターミナルのインストール

注意：この記述はすでに古い。いずれ削除予定。現在は後述する [# 追記：新たな選択肢 - WSLtty](#追記新たな選択肢---wsltty) の方を参照してほしい。

[Hyper](https://hyper.is)

を導入する。

Hyperの環境設定で、以下の行を設定する。これで、Hyperで起動するシェルはWSL環境でデフォルト扱い（複数のLinuxがインストールされている場合の話）になっているLinux環境のシェルになる。

```
shell: 'C:\\Windows\\System32\\bash.exe',
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/262898/116a0038-4b26-f8d2-e848-7ace41260a15.png)

## WindowsのファイルパスをWSL環境のパスに変換する

Windowsのエクスプローラからフォルダなどをターミナルウィンドウにドラッグ＆ドロップすると、Windows形式のファイルパスがターミナルに入力される。これを、WSL形式のパスに変換するシェル関数を用意した。

```
cdw () {
    cd "$(echo $1 | sed -e 's/\(.\):/\/mnt\/\L\1/' -e 's/\\/\//g')"
}
```

これを`.bashrc`などに記載しておく。

そして、 `$ cdw ` と打ってから、Windowsのエクスプローラのフォルダをドラッグアンドドロップする。（Windows形式の）パスが入力されるので、そのままエンターキーを押すと、望みのパスに問題なく移動することができる。

![cdw.gif](https://qiita-image-store.s3.amazonaws.com/0/262898/f9e2c5bc-18a6-99fd-cf76-5bb993f3022e.gif)

　これが、普通のコマンドプロンプトだと、「パスにスペースが含まれるフォルダ」はダブルクォーテーションでパスが囲まれて入力されるのでうまくいく。しかし、「パスにスペースが含まれないフォルダ」はダブルクォーテーションに囲まれずにパスが入力されるために、\が解釈時点で捨てられてしまう挙動によって正しく動作しない現象に悩まされた。
　Hyperターミナルソフトは、どのようなフォルダでも常にシングルクォーテーションで囲むという一貫した動作であったので、今回はWindowsにおけるターミナルソフトはHyperに落ち着いた。この問題が解決する以外にも、Hyperには多くの魅力があると感じた。

## スニペットツール
　スニペットツールとは、[TextExpander](https://textexpander.com)に代表される、いわゆる短い省略形をタイプするだけで、長いテキストに展開してくれる入力補助ツールだ。
　TextExpanderだと、Hyperとの組み合わせではうまく動作しなかったため、最近マルチプラットフォーム化を果たした競合ソフトである[PhraseExpress](https://www.phraseexpress.com/)に乗り換えた。こちらはHyperでうまく動作する。
　TextExpanderはサブスクリプション課金形式に移行したことで世の不満が出ているようだ。個人的にそれくらい大目に見ればいいとは思うが、PhraseExpressの方が（特にWindows版は）多機能に感じる。今後はPhraseExpressの方がシェアを伸ばすかもしれない。

追記：PhrageExpressとHyperの組み合わせでは、ある程度以上の長さのスニペットの展開でエラーが起きるようだ。

# WSL環境以外のシェルから、WSLデフォルトLinuxのシェル環境のコマンドを利用する

　コマンドプロンプト/PowerShell/MSYS いずれからでも、

```
$ wsl ls
```

　などと、wslの後に実行したコマンドを続けることで、WSL環境でデフォルト指定のLinux環境のコマンドを実行できる。

# 追記：新たな選択肢 - WSLtty

https://github.com/mintty/wsltty

WSLに特化したターミナル。前述のcdwなど必要なく、そのままターミナルにフォルダを放り込めば、`/mnt/c/`形式としてパスを入力してくれる。
スニペットソフトの対応については、こちらはPhrageExpressが全くダメで、逆にTextExpanderでは（長いスニペットも含め）全く問題なかった。現在はWSLttyとTextExpanderに落ち着いている。

# WSL環境から、指定したディレクトリパスをWindowsエクスプローラで表示する

`judge2020` という人が作った下記のシェルスクリプトが便利だ。

https://gist.github.com/judge2020/4450bc62df8adeeb29f02bd5524ab3db

```
$ explorer .
```

　で現在のカレントディレクトリをエクスプローラで開くことができる。

# WebStormなどの統合開発環境でWSLシェルを利用する

WebStormなど、内部でターミナルを用意している開発環境では、大抵は使用したいシェルを指定できる。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/262898/80e40305-57d0-7cad-c8c5-c5514421f1e6.png)

　Node.jsなど、Windowsではあまりサポートが充実していない環境はWSLのLinuxで構築してしまい、WebStormからはWSLシェルを指定することで、Windowsへの親和性が薄い開発環境も問題なく利用することができる。

# WSL環境で立てたローカルサーバーはWindows側からアクセスできる

例えば、WSL環境にNode製のhttpサーバーである`http-server`をインストールし、以下のようにすると。

```
$ http-server
Starting up http-server, serving ./
Available on:
  http://192.168.91.1:8080
  http://192.168.217.1:8080
  http://172.24.87.1:8080
  http://127.0.0.1:8080
  http://192.168.100.8:8080
Hit CTRL-C to stop the server
```

問題なくWindows側のWebブラウザで `http://localhost:8080` とアクセスできる。

# WSLでのSSHポートフォワーディングはWindowでも利用できる。

　WSLでSSHポートフォワーディングしたポートは、実はWindowsからも利用することができる。これならば、SSH関連はMSYSやWindows系の独自のSSHツールよりも、より安定したWSL Linux側のSSHに完全に任せることができるだろう。

例えば、rmateという仕組みを使い、ローカルマシンのWSL LinuxからSSH接続したサーバー上のファイルを、ローカルマシンWindowsのVisual Studio Codeで編集することができる。

（設定方法については他の人のQiita記事「[Vagrant上のファイルをVScodeで編集 for Mac](https://qiita.com/daiki7nohe/items/714c0c122f6ca7586f3b)」などを参照のこと。MacやVagrantに限らず設定は基本同じである）

on WSL Linux

```
$ ssh -i ~/.ssh/hoge.pem centos@example.com -R 52698:localhost:52698
```

on Windows VS Code

![image.png](https://qiita-image-store.s3.amazonaws.com/0/262898/a5b8f21a-ad50-356f-ae0c-4113a23ea295.png)

on Server Linux

```
$ rmate hoge.txt
```

# fishシェル
　個人的にBashよりもFishを好むため、以下のような環境を整えた。

## 常時Fishにする

以下のシェルスクリプトを`.bashrc`などに記載しておくことで、シェル起動時に即座にfishに切り替わる。

```bash
# Fish
if [ -z "$FISH" ] && [ "${FISH:-A}" = "${FISH-A}" ]; then # if $FISH is undefined
  export FISH=1
fi
if [ $((FISH)) != 0 ]; then
    case $- in
        *i*) exec fish;;
        *) return;;
    esac
fi
```

bashに戻りたい場合は、下記コマンドを実行する。

```
set -x FISH 0; bash
```

bashから再びfishに切り替えたい場合は、下記コマンドを実行する。

```
FISH=1 fish
```

自分は、これらのコマンドの入力が面倒と感じ、PhraseExpressでそれぞれ`f2b`、`b2f`としてスニペット登録している。

## Fishでも`cdw`コマンドを使う

以下を、`~/.config/fish/config.fish`に記載する。

```
function cdw
    cd (wslpath $argv[1])
end
```

　wslpathコマンドは、Windows10 1803アップデートから含まれるようになった、Windows形式のファイルパスをWSL形式に変換するコマンドである。しかし、コマンドプロンプトやBashでは、このwslpathは完ぺきな利便性を提供してくれないように感じる。Bashの方で、sedコマンドを利用した`cdw`コマンドを自前で用意（といってもどこかのStackOverflowを参考にした）したのは、そのためである。
　しかし、HyperとFishの組み合わせであれば、wslpathコマンドはうまく機能する。
　Bashの時と同様に、エクスプローラからフォルダをドラッグ＆ドロップして、`cdw`移動することができる。

## Fishプロンプトカスタマイズ

　余談に近くなるが、個人で使っているプロンプトカスタマイズである。Gitのカレントブランチなどの情報も表示されるので、多少は便利かと思う（どこかでググった情報を参考にしたが、失念してしまった）。

```
# Fish Command Prompt Custumize
function fish_prompt --description 'Write out the prompt'
    # Just calculate these once, to save a few cycles when displaying the prompt
    if not set -q __fish_prompt_hostname
    set -g __fish_prompt_hostname (hostname|cut -d . -f 1)
    end

    if not set -q __fish_prompt_normal
    set -g __fish_prompt_normal (set_color normal)
    end

    if not set -q __git_cb    set __git_cb ":"(set_color brown)(git branch ^/dev/null | grep \* | sed 's/* //')(set_color normal)""
    end
    switch $USER
    case root

    if not set -q __fish_prompt_cwd
        if set -q fish_color_cwd_root            set -g __fish_prompt_cwd (set_color $fish_color_cwd_root)        else            set -g __fish_prompt_cwd (set_color $fish_color_cwd)
        end
    end
    printf '%s@%s:%s%s%s%s# ' $USER $__fish_prompt_hostname "$__fish_prompt_cwd" (prompt_pwd) "$__fish_prompt_normal" $__git_cb

    case '*'
    if not set -q __fish_prompt_cwd
        set -g __fish_prompt_cwd (set_color $fish_color_cwd)
    end

    printf '%s@%s:%s%s%s%s > ' $USER $__fish_prompt_hostname "$__fish_prompt_cwd" (prompt_pwd) "$__fish_prompt_normal" $__git_cb

    end
end
```

以下のような感じになる。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/262898/d06e39d4-b8f6-0622-26b6-a4c075345189.png)

# ディスクIO性能について

　詳しくは調べられていないが、WSL環境はディスクIOの性能に課題があるようだ。
　特にIO処理が多く伴うnode.jsのnpmやyarnのでのパッケージインストールではMacと比べて大幅に遅いなど、まだ問題点は散見される。
  https://github.com/yarnpkg/yarn/issues/990
　これについては、とりあえずWindows Defenderなどのファイルアクセスをいちいちチェックするようなアンチウイルスソフトの監視で開発系のディレクトリを除外設定すると、だいぶ改善する模様。

# まとめ

　*nix環境との互換とGUIソフトウェアの充実、セットアップの利便性という点で、今まではmacOSが開発環境として好まれていた。
　だがこの状況もやがて変わり、Windowsが死角のない最強開発プラットフォームの座に再び返り咲くと筆者は考える。