(編集途中あり)VSCodeっぽい開発環境をvim + tmuxで構築 〜Windows・MacOSで変わらない開発環境を求めて〜

# 開発環境を構築するうえで重要なこと
**2020/3/22時点で、試行錯誤がまだ足りない箇所は編集途中と表示してあります。ただ、公開せずに下書き状態にするのももったいないので一旦公開して安定してきた部分は追記していく予定です。**

開発環境を構築する上で、結構重要なのって「**この操作って実現できるの？**」ってことだと思います。

普段できていることができなくなったらストレスですからね。

ただ、色々試して実際に構築したからわかることなのですが、**VSCodeで十分です**。というか、VSCodeって偉大だなとさえ思っています。

なぜなら、

* インストールしたら基本的な機能が揃っている
* ないものもプラグインを入れればいいので、困らない
* そして、何より軽い

からです。

並行して移行している期間中は、何度かVSCodeだとやっぱりこの操作楽だよなーということがありました(笑)

そして、ファイラーを使った検索とかはvimのプラグインを使ったほうが速いんだろうなーと思っていたのですが、使い方によって重かったりします・・・
そこらへんはまだまだ知識不足なのでこれから改善していく予定です。

# 環境
自宅ではMacOS、職場ではWindows10を使っているのでWindows・MacOSで変わらない開発環境を目指します。

* Windows10
* MacOS High Sierra

Linux環境では試していないので動くかわかりません・・・

# 最終的にたどりついた構成
シンプル構成です。
後述しますが、**Windowsの端末エミュレーターはHyper + tmuxを使う運用ができなかったため、Git bashを採用しています。**

| | Windows | Mac |
| ---- | ---- | ---- |
| 端末エミュレーター | Git bash | Hyper |
| 端末多重接続ソフト | tmux | tmux |
| シェル | bash | bash |
| テキストエディタ | vim | vim |
| バージョン管理 | Git | Git |

# この構成にたどりつくまでにやったこと
**windows上でlnコマンドなどもLinuxと同様の動きをするようにしたいと思い、WSLに走る。**

=> Hyperからwslのbashを使って､wslのbashからローカル環境のVM起動して作業するには結構時間がかかる上に、最後の最後でコケて色々ためしたけどダメで断念・・・あと、仮想環境が絡んでくるとただでさえハードルが高いのに、Windows上のLinux環境からローカル環境のVagrant等でさらにWindows上に仮想環境を構築したりとなると鬼・・・

**まあ、最悪lnコマンドはなんとかするとして、次にwindowsでもtmuxを使いたい。端末エミュレーターはHyperがいい！**

=> Windowsで端末エミュレーターにHyperを使うとtmuxが動かない・・・色々調べて`git-bash.exe`とか`mintty.exe`とか動く環境だとttyコマンドを打つと、`/dev/pty1`とか`/dev/ttys`(これはMacの場合)とか返ってきて、Hyperでシェルに`bash`を指定した動かない環境だと`/dev/cons0`とかが返ってくることがわかった。Hyperは端末エミュレーターなのでシェルを指定できるけど、`git-bash.exe`とか`mintty.exe`を指定すると別窓で開いてどうにもならなかったので断念・・・

**最後は、WindowsではHyperを使うことは素直に諦めました・・・**
(諦めるまでに相当粘りました・・・)

最終的に、Windowsではtmuxが動く`git-bash.exe`を端末エミュレーターとして使うことにしました。

WindowsとMacでソフトの差はあるものの、**操作インターフェースはtmuxとvimに集約されるのでOSが異なってもたぶん快適でしょう。**

# インストール
## Windows
### Git for Windows
まずは、Gitを使うのに必要なGit for Windowsをインストールします。
これで、**Gitとgit bashとvim(Git for Windows付属)が使える環境が手に入ります。**
[Git for Windows](https://gitforwindows.org/)

![スクリーンショット 2020-03-22 1.06.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163887/604671a4-017d-92d9-97f2-75ab7c5acc97.png)

### tmux
Windowsでtmuxを導入するために、pacmanを使います。
pacmanを使うために、MSYS2をインストールします

1. [MSYS2 homepage](https://www.msys2.org/)から`msys2-x86_64-20190524.exe`をインストール
![スクリーンショット 2020-03-22 1.07.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/163887/f9e91b84-c065-be60-9ede-12d8d4a5b6ee.png)

2. `C:\msys64\msys2.exe`を起動
3. `pacman -S tmux`を実行
4. `C:\msys64\usr\bin`に`tmux.exe`と`msys-event-2-1-6.dll`を`C:\Program Files\Git\usr\bin`にコピーします。
5. `C:\Program Files\Git\git-bash.exe`を起動して、`tmux -V`でバージョンがでればOK

これで、**git-bashからtmuxが使えるようになります。**

### Make
dotfilesから設定ファイルを展開する際に`make`コマンドを使うのでインストールします。不要であれば飛ばして構いません。

この記事を参考にインストールしました。
[Windows環境でmakeコマンドを利用する \- MRが楽しい](http://bluebirdofoz.hatenablog.com/entry/2019/10/24/221517)

## Mac
### Homebrew
Macのパッケージマネージャーです。
「homebrew インストール」とかでたくさん出てくるので、インストール方法については割愛。

### Hyper
公式サイトからインストール。
[Hyper™](https://hyper.is/)

### vim
Macにデフォルトでvimが付属していますが、バージョンが低いので、Homebrew経由でmacにvimをインストール

```
brew install vim
```


### git
Macにデフォルトでgitが付属していますが、どうせならパッケージマネージャーで管理したいので、Homebrew経由でmacにgitをインストール

```
brew install git
```

### Make
Macも同じく`make`コマンドが使えるようにします。
私の場合はすでに使えたので使えなければ、記事を探してインストールしましょう。

# 設定
今後変わる可能性がありますが、現時点の設定です。

## 設定ファイルの運用について
設定ファイルはGithubにdotfilesをホスティングして管理してます。
ソフトもすぐにインストールできるもので構成しているので、あとはワンコマンドでdotfilesを展開すればすぐに普段と変わらない環境が出来上がります。

以前、書いたdotfilesに関する記事(WindowsでもMacでも使えるという点が快適ライフを送る上で超重要です。)
[挫折しないdotfiles運用 〜Windows・MacOSで使える設定ファイルを目指して〜 \- Qiita](https://qiita.com/snyt45/items/cd3a538beb254bf2840b)

私のdotfilesです。日々成長中です。
[snyt45/dotfiles](https://github.com/snyt45/dotfiles)

## Hyper

### hyper.js
基本から変わっている部分だけ。
hyper-material-themeの設定を追加しています。

```js

//////////////////////////////////////
// hyper-material-theme
//////////////////////////////////////
  MaterialTheme: {
     theme: 'Palenightr',
     backgroundOpacity: '0.7',
     accentColor: '#64FFDA',
     vibrancy: 'dark'
  },
```

### hyper.jsのクロスプラットフォーム化
**windowsではHyperを使わずにGit bashを使うことにしたのでクロスプラットフォーム化は必要なくなりましたが、一応残しておきます。**
~~**残念なことにhyper.jsのシェルの設定回りだけWindowsとMacで差が出てきます。**~~

そのため、あらかじめdotfilesの中にWindows用とMac用のhyper.jsを用意しておいて、dotfilesを展開するときに下記シェルスクリプトでWindowsならWindows用、MacならMac用のhyper.jsをホームディレクトリに展開するようにしています。
(これらのファイルはdotfilesのconfig以下に配置しています。)

また、Windowsで起きた事象ですがHyper3.2で~/.hyper.jsを配置してもHyperが.hyper.jsを削除してしまいます。
そのため、Windowsの場合はシェルスクリプト内で展開先を`$HOME/AppData/Roaming/Hyper/$HYPER_JS`とするとうまくいきました。

> 新しいバージョンは、古いバージョンの％USERPROFILE％.hyper.jsではなく、％APPDATA％\ Hyper.hyper.jsの設定ファイルを指しているようです。
古い場所から古いファイルを取得し、新しい場所に貼り付けるだけで、すべての設定が元に戻ります。
[Hyper 3\.0\.0 deleted settings/configuration \(\.hyperjs\) · Issue \#3594 · zeit/hyper](https://github.com/zeit/hyper/issues/3594)


```shell

#!/bin/bash

##############################################################################
# 定数
##############################################################################
DOTPATH=~/.dotfiles;
HYPER_JS=.hyper.js;
HYPER_JS_PATH=config/hyper_js_preferences;
WINDOWS_HYPER_JS=$HYPER_JS_PATH/.windows.js;
OTHER_HYPER_JS=$HYPER_JS_PATH/.other.js;

##############################################################################
# hyper.jsのクロスプラットフォーム化
##############################################################################
if [ "$(uname)" == "Darwin" ]; then
  echo Mac
  ln -snfv "$DOTPATH/$OTHER_HYPER_JS" "$HOME/$HYPER_JS"
elif [ "$(expr substr $(uname -s) 1 5)" == "MINGW" ]; then
  echo Windows
  ln -snfv "$DOTPATH/$WINDOWS_HYPER_JS" "$HOME/AppData/Roaming/Hyper/$HYPER_JS"
elif [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then
  echo Linux
  ln -snfv "$DOTPATH/$OTHER_HYPER_JS" "$HOME/$HYPER_JS"
else
  echo Unknown OS
fi
```

### プラグイン

プラグイン系で使うコマンドです。

```bash

# 一覧
hyper list
# インストール
hyper i プラグイン名
# アンインストール
hyper u プラグイン名
```

### 入れたプラグイン
* hyper-material-theme
    * Hyperのマテリアルテーマ
* hyper-tab-icons-plus
    * タブタイトルにアイコンを表示してくれる
* hyper-search
    * ターミナル上で検索ができるようになる。

### 諸事情で入れなかったプラグイン
* hyperterm-summonは、ショートカットキーでHyperを呼び出す便利なプラグインですが、Windowsでは使えないので入れてないです。
* hypercwdは、新しいタブを開く際にカレントディレクトリと同じ階層で開く便利なプラグインですが、WindowsでHyperのタブ分割とかのショートカットキーが使えなくなったので入れてないです。
* キーマップ系もよさげなのでありましたが、開発が止まっていたりデフォルトのキーマップを変えるだけでも済むので入れてないです。
* キーマップは[公式サイト](https://hyper.is/#keymaps)から見れます。hyper.jsで変更もできます。

## vim
### プラグイン
プラグイン管理には、NeoBundleを使っています。

**vimrcに下記のように記述するだけで、vimを開いたときにすぐにプラグインが使える状態になります。
新しくプラグインをインストールするときもvimrcに追記するだけなので、はっきりいって超便利です。**
NeoBundleの作成者もこのvimrcの記述を考えた人も神ですね。
こういう誰かの努力のおかげで便利な環境で仕事できるんだなーとしみじみ思いますね。

* NeoBundleが未インストールであればgit clone
* 未インストールのVimプラグインがある場合、インストールするかどうかを尋ねてくれる


```vim

"----------------------------------------------------------
" NeoBundle
"----------------------------------------------------------
if has('vim_starting')
    " 初回起動時のみruntimepathにNeoBundleのパスを指定する
    set runtimepath+=~/.vim/bundle/neobundle.vim/

    " NeoBundleが未インストールであればgit cloneする
    if !isdirectory(expand("~/.vim/bundle/neobundle.vim/"))
        echo "install NeoBundle..."
        :call system("git clone git://github.com/Shougo/neobundle.vim ~/.vim/bundle/neobundle.vim")
    endif
endif

call neobundle#begin(expand('~/.vim/bundle/'))

" インストールするVimプラグインを以下に記述
" NeoBundle自身を管理
NeoBundleFetch 'Shougo/neobundle.vim'

"============================="
  " こんな感じでプラグインを記述
  " NeoBundle 'tpope/vim-fugitive'
"============================="

call neobundle#end()

" 未インストールのVimプラグインがある場合、インストールするかどうかを尋ねてくれるようにする設定
NeoBundleCheck
```

### vimrc全体
vimrcについては、まだまだ調整中なので改善の余地は見る人から見たらたくさんあるかと思いますが、
とりあえず、今の状態をはっつけます。

基本的には、コメントを書いているのでざっくりと何をしているかはわかるかと思います。

```vim

"----------------------------------------------------------
" NeoBundle
"----------------------------------------------------------
if has('vim_starting')
    " 初回起動時のみruntimepathにNeoBundleのパスを指定する
    set runtimepath+=~/.vim/bundle/neobundle.vim/

    " NeoBundleが未インストールであればgit cloneする
    if !isdirectory(expand("~/.vim/bundle/neobundle.vim/"))
        echo "install NeoBundle..."
        :call system("git clone git://github.com/Shougo/neobundle.vim ~/.vim/bundle/neobundle.vim")
    endif
endif

call neobundle#begin(expand('~/.vim/bundle/'))

" インストールするVimプラグインを以下に記述
" NeoBundle自身を管理
NeoBundleFetch 'Shougo/neobundle.vim'
" vim用のGitコマンドを追加
NeoBundle 'tpope/vim-fugitive'
" 末尾の全角半角空白文字を赤くハイライト
NeoBundle 'bronson/vim-trailing-whitespace'
" vim 用の統合ユーザインターフェース
NeoBundle 'Shougo/unite.vim'
" vimで非同期処理を実現する
NeoBundle 'Shougo/vimproc'
" ファイル操作をサポート(unite.vimとvimprocに依存)
NeoBundle 'Shougo/vimfiler'
" スクロール操作をなめらかにする
NeoBundle 'yuttie/comfortable-motion.vim'
" ウィンドウサイズの変更を簡単・高速にする
NeoBundle 'simeji/winresizer'

call neobundle#end()

" 未インストールのVimプラグインがある場合、インストールするかどうかを尋ねてくれるようにする設定
NeoBundleCheck

"----------------------------------------------------------
" ファイルタイプ別のVimプラグイン/インデントを有効にする
"----------------------------------------------------------
filetype plugin indent on

"----------------------------------------------------------
" 文字コード
"----------------------------------------------------------
" ファイル読み込み時の文字コード
set encoding=utf-8
" Vim Script内でマルチバイト文字を使う設定
scriptencoding utf-8
" 保存時の文字コード
set fileencoding=utf-8
" 読み込み時の文字コードの自動判別. 左側が優先される
set fileencodings=ucs-boms,utf-8,euc-jp,cp932
" 改行コードの自動判別. 左側が優先される
set fileformats=unix,dos,mac
" □や○文字が崩れる問題を解決
set ambiwidth=double

"----------------------------------------------------------
" スワップファイルを作成しない
"----------------------------------------------------------
" viminfo ファイルを作成しない
set viminfo=
" swap ファイルを作成しない
set noswapfile
" バックアップファイルを作成しない
set nobackup

"----------------------------------------------------------
" クリップボード機能
"----------------------------------------------------------
" vimのヤンク、プット有効
" Ctrl+c、Ctrl+v有効
set clipboard=unnamed,autoselect

"----------------------------------------------------------
" 行番号の表示
"----------------------------------------------------------
set number

"----------------------------------------------------------
" ステータスライン
"----------------------------------------------------------
" ステータスラインを常に表示
set laststatus=2
" 現在のモードを表示
set showmode
" 打ったコマンドをステータスラインの下に表示
set showcmd
" ステータスラインの右側にカーソルの位置を表示する
set ruler
" ステータスラインに現在のgitブランチを表示する
if neobundle#is_installed('vim-fugitive')
  set statusline+=%{fugitive#statusline()}
endif

"----------------------------------------------------------
" デフォルトのファイラー
"----------------------------------------------------------
" デフォルトをVimfilerにする｡:e .でvimfilerが開けるようになる｡
let g:vimfiler_as_default_explorer = 1

"----------------------------------------------------------
" キーマッピング(ノーマルモード)
"----------------------------------------------------------
" ウィンドウを下に移動
nnoremap sj <C-w>j
" ウィンドウを上に移動
nnoremap sk <C-w>k
" ウィンドウを右に移動
nnoremap sl <C-w>l
" ウィンドウを左に移動
nnoremap sh <C-w>h
" ウィンドウを水平分割(Hyperのキーマッピングに合わせる)
nnoremap se :<C-u>sp<CR>
" ウィンドウを垂直分割(Hyperのキーマッピングに合わせる)
nnoremap sd :<C-u>vs<CR>
" 選択しているバッファ以外を閉じる
nnoremap <silent> <Space>o  :only<CR>
" GIt 過去の変更を辿る
nnoremap <silent> <Space>gb :Gblame<CR>
" Git 差分を表示する
nnoremap <silent> <Space>gd :Gdiff<CR>
" Git ステータス画面を開く
nnoremap <silent> <Space>gs :Gstatus<CR>

"----------------------------------------------------------
" 自動コマンド
"----------------------------------------------------------
" :Unite bookmark後にEnter押下でそのディレクトリをVimfilerで開く
autocmd FileType vimfiler call unite#custom_default_action('directory', 'cd')

"----------------------------------------------------------
" ctagsのtagsファイル読み込み
"----------------------------------------------------------
set tags=./.tags;
```

## tmux(編集途中)

# VSCodeっぽい操作(編集途中)
## 必須のやつ(編集途中)
* ターミナル操作
    * ウィンドウ
        * ウィンドウ間移動
        * ウィンドウ分割
    * タブ
        * タブ間移動
        * タブ分割
* ファイル操作
    * ディレクトリ移動
    * 全文検索
    * ファイル名検索
    * 関数ジャンプ
* Git操作
    * コミット履歴から差分を見たい
    * コミット一覧からファイルを選んで差分を見たい

## あると便利なやつ(編集途中)

# 改善ポイント(編集途中)
気づいたら追記していきます。

* ideコマンドみたいな独自コマンドでカスタムレイアウトの展開
* 複数画面のcdディレクトリ同時移動