Windows10での快適なCLI環境の構築 [WSL+Cmder+powerline](Pythoner向け)

WindowsのデフォルトのCLI環境は極めて使いにくいです．
イライラした経験をお持ちの方も多いかと思います．

また，WindowsでPythonを使う時は基本Anacondaを使う羽目になっていました．
Anacondaは"不必要なパッケージのインストール"や"環境変数の勝手な書き換え"，"ライブラリの管理がcondaとpipで二元化してしまう"など，個人的にはあまり好きではありません．

これらを一挙に解決する方法として，Windows Subsystem for Linuxを用いた環境構築の備忘録を残します．
ゴリゴリにシェルを魔改造する方向けではなく，**ライトユーザー向けの設定**なのでご了承ください．

# 1. 概要
before
![2018-11-30 (2).png](https://qiita-image-store.s3.amazonaws.com/0/181545/a2d1bd31-94f1-8f4d-bb6b-9c79e1b45013.png)

after
![2018-11-30 (3).png](https://qiita-image-store.s3.amazonaws.com/0/181545/ab1158e1-0a0e-b602-b8a6-de260b169965.png)

## 1.1 使用したもの
+ OS: Windows10(バージョン1803)
+ Windows Subsystem for Linux(WSL)
+ Cmder
+ zsh (oh-my-zsh)
+ pyenv
+ powerline-shell

## 1.2 デフォルトで入っていてほしいもの
+ git (入ってない方は[こちら](https://qiita.com/toshi-click/items/dcf3dd48fdc74c91b409)がおすすめです)
+ vim

## 1.3 本記事で説明しないもの
+ 各アプリケーションの詳しい説明

# 2. WSLのインストール
+ コントロールパネルを開きます．(ご存知かと思いますが，スタートメニューの`WIndows システムツール`の中にあります）
+ `プログラム`→`Windowsの機能の有効化または無効化`をクリックします．
+ Windows Subsystem for Linuxのチェックボックスを入れてOKして，ダウンロードが終わったらPCを再起動します．  
![2018-11-30 (6).png](https://qiita-image-store.s3.amazonaws.com/0/181545/a3f02e07-7dab-4601-d727-c71843a3bed7.png)
+ 再起動したら，ブラウザから[https://aka.ms/wslstore](https://aka.ms/wslstore)を開きます．
+ 好きなディストリビューション（Ubuntu）を選んでダウンロードし，終わったらUbuntuを開きます．
+ Ubuntuを開いたら，ユーザー名とパスワードを設定して，以下のコマンドを打ちます．

```shell:initial_setting_ubuntu
$ sudo apt update
$ sudo apt upgrade
$ sudo apt-get install zsh
```
+ <font color='red'>**ホームディレクトリをWindowsのホームディレクトリを一致させたい場合は[こちら](https://qiita.com/funafuna/items/c3bb78a546cf2605205d)を参考にしてください．**</font>


# 3. Cmderのインストールと設定
#### 3.0 フォントのインストール
+ 後々，必要なフォントを先にインストールしておいた方が楽なので，ここでインストールします．
+ [Myrica-MM.ttf](https://github.com/pomutemu/milly/blob/master/Myrica-MM.ttf)をダウンロードします．(Downloadボタンをクリック)
+ コントロールパネルから`デスクトップのカスタマイズ`→`フォント`を選んで，先程ダウンロードした`Myrica-MM.ttf`をドラッグアンドドロップしてインストールを完了します．  
<img src=https://qiita-image-store.s3.amazonaws.com/0/181545/226de016-8e5d-ffb4-6dae-2af405128d90.png width=50%>


#### 3.1 Cmderのインストール
+ [Cmderの公式](http://cmder.net/)にアクセスして，`Download Mini`を行います．
+ ダウンロードしたファイルは`Users/<ユーザー名>/cmder`等に解凍して配置します．
+ コマンドプロンプトから起動できるようにしたい場合は，配置した場所に環境変数を通します．（オプション）

#### 3.2 設定
+ cmder.exeを起動します．
+ 下にあるタブバーを右クリックして`Settings`を開きます．(Win+Alt+pでもショートカットできます)  
<img src=https://qiita-image-store.s3.amazonaws.com/0/181545/442dc40d-b636-a630-db80-18b327c1cc8b.png width=30%>
+ `General`→`Fonts`を選択し，Main console fontとAlternative fontの双方を`Myrica MM`に変更します．
+ `Startup`→`Tasks`を選択します．
    + 下部の+ボタンをクリックして新しいTaskを設定します．
    + `Default task for new console`にチェックを入れて
    + 右下の大きな空白の部分に`C:\Windows\System32\bash.exe -cur_console:p -c zsh`と入力します．
    + `Save settings`をクリックして設定を保存し，cmderを再起動します．  
<img src=https://qiita-image-store.s3.amazonaws.com/0/181545/2851554d-ea72-7369-0901-070ed290a95a.png width=70%>

# 4. oh-my-zshの導入
+ bashよりもzshの方が補完等がよいので，zshを導入します．プラグイン管理としてoh-my-zshを使用します．
+ ログインシェルをzshに変更します．

```shell:zsh_setting
$ which zsh
## /usr/bin/zsh
$ chsh
## Changing the login shell for root
## Enter the new value, or press ENTER for the default
##     Login Shell [/bin/bash]: ここに"$ which zsh"の結果をはりつける
# ここまで設定したらPCを再起動します．
```

+ このままだと素のzshなので，プラグイン管理としてoh-my-zshを導入します．zplug等もありますが，なんだかんだoh-my-zshがお手軽なのでここはoh-my-zshを利用します．

```shell:oh-my-zsh
$ sh -c "$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"
```

+ いい感じに.zshrcをいじりましょう．Python使用者のおすすめはこんな感じです．

```shell
$ vim ~/.zshrc
```
```shell:.zshrc
export ZSH="/home/user/.zplug/repos/robbyrussell/oh-my-zsh"
ZSH_THEME="candy"
plugins=(
  git pip pyenv virtualenv
)
source $ZSH/oh-my-zsh.sh
```

# 5. 細かな設定
+ このままだとbeep音がうるさすぎるのでbeep音を消します．（この設定の記事がなかなか見つからなくて苦労しました．）
+ また，vimで一部キーがうまく動作しないことがあるので，そちらも設定します．

```shell:detail_settings
$ echo "setopt no_beep" >> ~/.zshrc
$ echo "set belloff=all" >> ~/.vimrc
$ echo "set term=builtin_ansi" >> ~/.vimrc
$ exec $SHELL
```

# 6. Powerlineの導入
Python使用者はPowerline-shellを入れると更に便利です．

#### 6.1 python環境の構築
+ Powerline-shellはPython環境が必須です．
+ Python環境をインストールします．バージョン管理はpyenvとvirtualenvを用いて行います．
+ pyenvとvirtualenvをインストールしましょう．

```shell:pyenv
$ apt-get install -y make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev
$ git clone https://github.com/pyenv/pyenv.git ~/.pyenv
$ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshenv
$ echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zshenv
$ echo -e 'if command -v pyenv 1>/dev/null 2>&1; then\n  eval "$(pyenv init -)"\nfi' >> ~/.zshenv
$ exec $SHELL
$ git clone https://github.com/pyenv/pyenv-virtualenv.git $(pyenv root)/plugins/pyenv-virtualenv
$ echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.zshenv
$ exec $SHELL
```

+ 好きなバージョンをインストールしましょう．例えば，以下のように設定すると良いでしょう．
+ pyenvの使い方は[こちら](https://qiita.com/akidroid/items/9f983f875e98eae2fda8)を参考にしてください．

```shell:python_initial_installation
$ pyenv install 3.6.0
$ pyenv virtualenv 3.6.0 default_env
$ pyenv global default_env
```

#### 6.2 Powerline-shellのインストール
+ インストールはpipを使う場合とgitを使う場合があります．詳しくは[公式](https://github.com/b-ryan/powerline-shell)を読んでください．今回はpipを使います．

```shell:install_powerline-shell
$ pip install powerline-shell
```

+ zshrcを変更します．oh-my-zshを入れている場合は，こんな感じにします．ZSH_THEME="candy"をコメントアウトして，その直後に以下の文言を挿入します．

```shell:.zshrc
setopt no_beep
export ZSH="/home/user/.zplug/repos/robbyrussell/oh-my-zsh"
# ZSH_THEME="candy"
#--------------- 挿入 ---------------#
function powerline_precmd() {
    PS1="$(powerline-shell --shell zsh $?)"
}
function install_powerline_precmd() {
  for s in "${precmd_functions[@]}"; do
    if [ "$s" = "powerline_precmd" ]; then
      return
    fi
  done
  precmd_functions+=(powerline_precmd)
}
if [ "$TERM" != "linux" ]; then
    install_powerline_precmd
fi
#--------------- 挿入 ---------------#

plugins=(
  git pip pyenv virtualenv
)
source $ZSH/oh-my-zsh.sh
```

+ やりたければ，表示のカスタマイズをします．私の設定は以下の通りです．

```shell
$ mkdir -p ~/.config/powerline-shell && powerline-shell --generate-config > ~/.config/powerline-shell/config.json
$ vim ~/.config/powerline-shell/original_color.py
```
```python:original_color.py
from powerline_shell.themes.default import DefaultColor
​
​
class Color(DefaultColor):
    USERNAME_FG = 15
    USERNAME_BG = 4
    USERNAME_ROOT_BG = 1
​
    HOSTNAME_FG = 15
    HOSTNAME_BG = 10
​
    HOME_SPECIAL_DISPLAY = False
    PATH_FG = 15
    PATH_BG = 70
    CWD_FG = 231
    SEPARATOR_FG = 0
​
    READONLY_BG = 1
    READONLY_FG = 7
​
    REPO_CLEAN_FG = 14
    REPO_CLEAN_BG = 0
    REPO_DIRTY_FG = 3
    REPO_DIRTY_BG = 0
​
    JOBS_FG = 4
    JOBS_BG = 8
​
    CMD_PASSED_FG = 15
    CMD_PASSED_BG = 3
    CMD_FAILED_FG = 15
    CMD_FAILED_BG = 1
​
    SVN_CHANGES_FG = REPO_DIRTY_FG
    SVN_CHANGES_BG = REPO_DIRTY_BG
​
    VIRTUAL_ENV_BG = 31
    VIRTUAL_ENV_FG = 231
​
    AWS_PROFILE_FG = 7
    AWS_PROFILE_BG = 2
​
    TIME_FG = 15
    TIME_BG = 64
```

```shell
$ vim ~/.config/powerline-shell/config.json
```
```json:config.json
{
    "segments": [
        "virtual_env",
        "uptime",
        "aws_profile",
        "ssh",
        "cwd",
        "git",
        "git_stash",
        "jobs",
        "newline",
        "set_term_title",
        "svn",
        "root",
        "time"
    ],
    "mode": "patched",
    "theme": "~/.config/powerline-shell/original_color.py"
}
```

# 7. 最後に
以上で設定は終わりです．
設定の結果，下のようなCLI環境を構築できます．
あとはお好みでzshのプラグイン等を入れてお試しください！

before
![2018-11-30 (2).png](https://qiita-image-store.s3.amazonaws.com/0/181545/a2d1bd31-94f1-8f4d-bb6b-9c79e1b45013.png)

after
![2018-11-30 (3).png](https://qiita-image-store.s3.amazonaws.com/0/181545/ab1158e1-0a0e-b602-b8a6-de260b169965.png)

# 8. 追記(2019.6.7)
+ <font color='red'> `unicode error`が起きる場合，以下の設定をすると治ります．</font>

```shell
$ export LC_ALL="en_US.UTF-8"
```

+ <font color='red'>**新しい仮想環境を設定するとpowerline-shellがないためバグります．**</font>
バグってしまった場合はpipでpowerline-shellを入れるとよいです．

```
$ pip install powerline-shell
```

+ <font color='red'>**稀に以下のようなエラーが起きます．gitのissueなどにも上がっておらず，原因は不明ですが．時間を置いたり，`ctrl+c`をしたり，シェルを再起動したりすると何事もなかったのように解決します．** </font>

```python:error
Traceback (most recent call last):                                                                                                                    
  File "/Users/Shintaro1/.pyenv/versions/default_env/bin/powerline-shell", line 11, in <module>
    sys.exit(main())
  File "/Users/Shintaro1/.pyenv/versions/3.6.5/envs/default_env/lib/python3.6/site-packages/powerline_shell/__init__.py", line 240, in main
    segment.add_to_powerline()
  File "/Users/Shintaro1/.pyenv/versions/3.6.5/envs/default_env/lib/python3.6/site-packages/powerline_shell/segments/uptime.py", line 16, in add_to_powerline
    minutes =  re.search('(?<=\:)\d{1,2}|\d{1,2}(?=\s+min)', raw_uptime).group(0)
AttributeError: 'NoneType' object has no attribute 'group'
```