APG4bから競プロに入門した初心者がスムーズに移行できるコーディング環境をNeovimで構築する

# はじめに
AtCoderの[APG4b](https://atcoder.jp/contests/apg4b)をサイト上でポチポチ進めていたのですが、補完効かなかったりカーソル移動が貧弱だったので、なるべくサイトと同じようなインターフェースにしつつ、ナイスなエディタ機能を使いたいな〜と思ってここ数日一生環境構築をしていました。
C++初めて触る人の参考になればいいなと思っています。

目標とするのは、

- **APG4bのインターフェースと可能な限り同じ形でかける**
- **かつブラウザ上でコーディングするより賢く(補完や改行、高速なカーソル移動、検索機能)コードがかける**
- **標準入力を叩き込んだら高速で結果が出る**

の3つです。APG4b終わったばっかマンが書いたんだな〜と思ってもらうとよいかもしれないです(もっとナイスな設定があったら教えてください)。
ちなみに最終的にこんな感じの画面ができます。
![IMG_2815.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238125/18f86aa5-cf6c-e989-1d30-99846a499acb.jpeg)

左上がソースコード、右上がその実行結果、下が対応する標準入力を入れる部分になっています。

# 本文
## neovimのインストール
プログラミング初めてでエディタに特にこだわりがないぜ❗️という人は多分VSCodeを使った方が(周りの話を聞く限り)よさそうです。けど、vimmerはかっこいいから…
ここにある設定は概ねvimでも動くと思いますが、一応neovimを使うことを想定しています(ぼくは元々vimを使っていたのですが、これを機にneovimに乗り換えました。自分の使っていた範囲では両者は相互互換です)。
neovimが自分のPCに入っていない場合は、[ここ](https://github.com/neovim/neovim/wiki/Installing-Neovim)を参考に入れます。ぼくはmacユーザーだったので、`brew install neovim` で入りました。

## neovimの設定とプラグインの導入
vimは自分好みにカスタムできるところと独特の操作感が魅力(?)です。
ガンガン設定を自分好みに書き換えガンガン拡張をブチ込みましょう。neovimの設定は`init.vim`というファイルに書いていきます。
たしかneovimインストール直後は`init.vim`が存在しないので作ります。

```shell
mkdir -p ~/.config/nvim # make a directory to save init.vim
cd ~/.config/nvim # move to the directory
nvim init.vim # make init.vim
```
## オートでテンプレートを読み込む
APG4bだとコードの最初のおまじない部分(`#include`と`using namespace`)をコピペすることが推奨されていますが、面倒なので自動でやってもらいたいです。
そこで、特定のディレクトリで`.cpp`ファイルを開いたときには、おまじないが入った状態からコーディングが始まってもらうようにしました。
まず適当なディレクトリにテンプレートを作りましょう。例えば、`nvim ~/.config/nvim/templates/atcoder.cpp`を開いて、

```c++:atcoder.cpp
// template for atcoder beginners
// when you create a *.cpp file, this template is loaded

#include <bits/stdc++.h>
using namespace std;

int main() {

}
```

これを書いて保存します。そしてさっき作った`init.vim`に、

```VimL:init.vim
autocmd BufNewFile ~/CompetitiveProgramming/AtCoder/*.cpp :0r ~/.config/nvim/templates/atcoder.cpp
```

などと書きます。これで、`~/CompetitiveProgramming/AtCoder`直下で新しく`.cpp`ファイルを開いたとき、さっき書いたテンプレートが自動で読み込まれてくれます。うれし〜😊


## オートで画面を分割し、上半分にソースコード、下半分に標準入力のフォームを作る
APG4bではソースコードの入力画面と標準入力の画面が上下に分かれてますね。それも自動でやってもらいましょう。
例えば`.bashrc`や`.zshrc`に次の処理を書き込みます。

```shell:.zshrc
function atcoder () {
  # if there has already been a stdin.txt, delete it and make a new file
  if [ -e stdin.txt ]; then 
    rm stdin.txt
  fi
  touch stdin.txt
  # make a new file and make an window for stdin.txt and broaden the window for the source codes
  nvim $1 -o stdin.txt -c "11 wincmd +" 
}
```

これで、`~/CompetitiveProgramming/AtCoder`にて`atcoder test.cpp`と打つとソースコードと標準入力画面が開きます。便利〜🤭
最後の`-c "11 wincmd"`は自分の環境だとこのぐらいがちょうどいいかな〜という感じなので適宜調整するといいと思います(ソースコードのウィンドウを11行分デカくしています)。
ここまでで`~/CompetitiveProgramming/AtCoder`にて`atcoder test.cpp`と打つと次のような画面が出ます。
ちゃんと画面が分かれて、上半分がソースコードのテンプレート、下半分が標準入力用の空ファイルになってくれていますね。
![スクリーンショット 2019-08-18 14.23.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238125/b7fff62d-a344-1d0f-b614-4c2efbce7e03.png)

## プラグインを入れる
ここまででガワはそれっぽくなったので、肝心のエディタ機能を追加します。
vimのプラグインはdeinというプラグインで管理すると便利です。
これに関する記述は先人が多数作ってくださっているので、細かいところはそちらに任せますが、次の内容を`init.vim`に書き込み、`init.vim`と同じ階層に`dein.toml`と`dein_lazy.toml`を作成して次のように書き込むと概ねうまくいくと思います。
それぞれのプラグインが何してくれているかはざっくり書いておきましたが、かいつまんでいうと次のことができるようになります。

- 補完が効くようになる
- vim上でC++が動かせる
- エラーチェックをしてくれる
- ステータスバーがイケてる感じになる

だいぶモダンなエディタ感が出てきました。うれし〜😊

```VimL:init.vim
" dein settings(plugin manager)
let s:dein_dir = expand('~/.cache/dein')
"dein original
let s:dein_repo_dir = s:dein_dir . '/repos/github.com/Shougo/dein.vim'

"if there is not dein, install it
if &runtimepath !~# '/dein.vim'
  if !isdirectory(s:dein_repo_dir)
    execute '!git clone https://github.com/Shougo/dein.vim' s:dein_repo_dir
  endif
  execute 'set runtimepath^=' . fnamemodify(s:dein_repo_dir, ':p')
endif

"start setting
if dein#load_state(s:dein_dir)
  call dein#begin(s:dein_dir)

  "prepare toml files. toml files hold plugins
  let g:rc_dir    = expand('~/.config/nvim')
  let s:toml      = g:rc_dir . '/dein.toml'
  let s:lazy_toml = g:rc_dir . '/dein_lazy.toml'

  "load toml and cache
  call dein#load_toml(s:toml,      {'lazy': 0})
  call dein#load_toml(s:lazy_toml, {'lazy': 1})

  "end installing
  call dein#end()
  call dein#save_state()
endif

"if there are plugins that have not installed yet, install them
if dein#check_install()
  call dein#install()
endif
```

```toml:dein.toml
[[plugins]]
repo = 'Shougo/dein.vim'

# custom status bar
[[plugins]]
repo    = 'vim-airline/vim-airline'
depends = ['vim-airline-themes']

[[plugins]]
repo = 'vim-airline/vim-airline-themes'

# color scheme
[[plugins]]
repo = 'joshdick/onedark.vim'
hook_add = '''
  colorscheme onedark
```

```toml:dein_lazy.toml
# completement
[[plugins]]
repo = "Shougo/deoplete.nvim"
on_i = 1
on_event = "InsertCharPre"
hook_source = """
  let g:deoplete#enable_at_startup = 1
  let g:deoplete#auto_complete_delay = 0
  let g:deoplete#auto_complete_start_length = 1
  let g:deoplete#enable_camel_case = 0
  let g:deoplete#enable_ignore_case = 0
  let g:deoplete#enable_refresh_always = 0
  let g:deoplete#enable_smart_case = 1
  let g:deoplete#file#enable_buffer_path = 1
  let g:deoplete#max_list = 10000
  set completeopt-=preview
"""

[[plugins]]
repo = "zchee/deoplete-clang"
on_ft = ["cpp", "cxx", "cp", "cc"]
depends = "deoplete.nvim"
hook_add = """
  let g:deoplete#sources#clang#libclang_path='/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/libclang.dylib'
  let g:deoplete#sources#clang#clang_header='/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang'
"""

# comletement for header files
[[plugins]]
repo = 'Shougo/neoinclude.vim'
on_ft = ["cpp", "cxx", "cp", "cc"]
depends = ['deoplete.nvim']

# error checker
[[plugins]]
repo = 'w0rp/ale'
hook_add = '''
    let g:ale_sign_column_always = 1
    let g:ale_fix_on_save = 1
    let g:ale_completion_enabled = 1
    let g:ale_sign_error = '⨉'
    let g:ale_sign_warning = '⚠'
    let g:ale_echo_msg_format = '[%linter%] %s [%severity%]'
    let g:ale_statusline_format = ['⨉ %d', '⚠ %d', '⬥ ok']
    let g:ale_linters = {
        \   'c' : ['clangd'],
        \   'cpp' : ['clangd']
    \}
'''

# quickrun
[[plugins]]
repo = 'thinca/vim-quickrun'
    hook_add = '''
    " keymapping
    nnoremap <Space><Space> :wa <bar> :wincmd <bar> :QuickRun <stdin.txt <CR>

    let g:quickrun_config = {}

    " when you run a cpp file, measure the execution time
    let g:quickrun_config['cpp'] = {
    \  'cmdopt' : '-std=c++14 -Wall',
    \  'hook/time/enable' : 1
    \}

    let g:quickrun_config['_'] = {
    \  'split' : 'vertical'
    \}
    set splitright
'''
```

quickrunの設定でノーマルモードのダブルスペースを標準入力を読み込んでquickrunにしているのが個人的なお気に入りポイントです。
ダブルスペースを**全てのウィンドウの編集内容を保存→左上のウィンドウに移動→標準入力を引き取ってquickrunを実行**に割り当てているので、**どこのウィンドウにいてもノーマルモードでダブルスペースを叩くとコードを実行してくれます**。うれし〜😊
上の方で`atcoder hoge.cpp`コマンドで`stdin.txt`を自動生成したので、こいつを勝手に読んでくれる感じです。
結果こんな感じになります。おつかれさまでした。
![スクリーンショット 2019-08-18 11.57.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238125/d1b29a9d-b87f-982e-238e-c5bbe8d6b3a1.png)


## その他細々したこと
### `#include <bits/stdc++.h>`
上の方でテンプレートに `#include <bits/stdc++.h>` と書き込みましたが、ローカル環境だと動きません。
[ここ](https://atcoder.jp/contests/apg4b/tasks/APG4b_ak#local_setting)を参考にヘッダーファイルを作りましょう。

### `init.vim`のカスタム
ここで紹介した以外にも色々`init.vim`はいじりようがあります。
例えばぼくは読み込むファイルの種類ごとにインデントの幅を変えたり(pythonは4、C++は2など)、方向キーで移動できるようにしたり、ctrl+a(e)で文頭(末)へ移動できるようにしたりしています。キーバインド(自分の好きなキーに特定の操作を割り当てること)はvimカスタムの醍醐味なので、各自自分にあった素敵バインドを設定してもらえればと思います。
先人の素敵セッティングスは「vimrc おすすめ」とかでググると大量に出てくるので是非参考にしましょう。
(`.vimrc`は無印vimの`init.vim`に当たるものですが、両者とも概ね同じ書き方で同じ機能が実現できます。)

### vimでneovimをエイリアスする
vimからneovimに乗り換えた人は特にですが、vimをnvimでエイリアスしましょう。
「`init.vim`を編集したのに設定が適用されてねえ❗️」というお前、お前はvimを開いている。

```shell:.zshrc
alias vim='nvim'
```

ちなみに元々vimを使ってたよ〜という人は`init.vim`のなかで`.vimrc`を読み込むこともできます。
新しく設定ファイル作るのが面倒な場合はそれでも良いと思います。ぼくも最初は`.vimrc`を読んでいたのですが、NeoBundleからdeinに乗り換えたりして大幅に内容が変わったので、結局新しく`init.vim`を作り直しました。

### My settings
ここまでの内容のほとんどは[ぼくのリポジトリ](https://github.com/Itto1992/neovim_settings)に置きました。[`.zshrc`の編集](https://qiita.com/Simossyi/items/3865b2b4154b6c795141#%E3%82%AA%E3%83%BC%E3%83%88%E3%81%A7%E7%94%BB%E9%9D%A2%E3%82%92%E5%88%86%E5%89%B2%E3%81%97%E4%B8%8A%E5%8D%8A%E5%88%86%E3%81%AB%E3%82%BD%E3%83%BC%E3%82%B9%E3%82%B3%E3%83%BC%E3%83%89%E4%B8%8B%E5%8D%8A%E5%88%86%E3%81%AB%E6%A8%99%E6%BA%96%E5%85%A5%E5%8A%9B%E3%81%AE%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E3%82%92%E4%BD%9C%E3%82%8B)部分以外は全部あると思います。
見た目の綺麗さ優先で`hook_add`をファイル分けしたりしてますが、基本的に内容は変わらないです。


# まとめ
- 指定したディレクトリ上で`atcoder hoge.cpp`と入力するとAPG4bのインターフェースlikeな画面が展開するようにした
- ソースコード上のノーマルモードでスペースを2回押すと標準入力を読み込んで結果を画面右上に開くようにした

# Future Work
自分の中で整理がついたらぼちぼち更新したり記事追加したりします

- 答え合わせ機能をつけたい
- quickrunのダブルスペースキーマップをatcoderディレクトリに限定する(`init.vim`でdein読んだあと、autocmdで入れると多分できますね)
- quickrunをvimprocで動かそうとすると出力が表示されない問題に永久に悩まされています助けてください