お前の.vimrcを見せろ



　これは [UEC Advent Calendar 2021](https://adventar.org/calendars/6400) 12月3日参加の記事です。本当はD言語について何かしら書こうと思ってたんですけど、課題が過大なので手っ取り早く書けそうなやつにしました。許してね。
　また、**この記事はエッセイみたいなものです**。電通大生にとって技術的に有益な話が今更あるわけではなく、ただこんな感じだよーっていうのを見てほしいだけです。ただ、もしこれがきっかけに有志が集まったらvimrc読書会をやってみたいとも思っています。

# はじめに（Vimあんま知らない人向け）
## Vim について
　**Vim**はテキストエディタの一種です。テキストエディタというと[Emacs](https://www.gnu.org/software/emacs/)とか[Visual Studio Code](https://code.visualstudio.com/)とか[Atom](https://atom.io/)あたりが有名でしょうか。コンパイラやリンカやデバッガなんかもくっついてるIDE(Integrated Development Environment, 統合開発環境)と違って、ただテキストファイルを編集するためだけに存在する潔いソフトウェアです。その歴史は結構古く、元々は**vi**という1976年に制作されたテキストエディタに遡ります。viは多くのUNIX系システムに搭載され、その後継であるVimは現在も多くの利用者を抱えています。同じような立ち位置のEmacsとはライバル関係にあり、どのエディタを使っているかという話題は[宗教戦争](https://qiita.com/JJ1LIS/items/22e406ec26ad1e5c6228)に繋がる恐れがあるので注意しましょう。
　近年の主流と言えばVSCodeやAtomですが、Vimにはそれらとは違う大きな特徴が一つあります。一つはGUIを必要とせずCUI上で動作すること。なんか知らんけどXが入ってないコンピュータとか遠くのサーバにSSHで入ってるときとかに重宝するわけです。そしてもう一つは「**モード**」と呼ばれる概念と特殊なキーバインドです。

### モード
　VimはCUIで動くため大仰なインタフェースは存在しません。更にマウスのような機器は使わず、なんなら矢印キーの使用を邪道と言う過激派もいます。したがって最低限のキーだけでテキスト編集を行う必要があり、そのためにモードという機能が備わっています。ユーザはその瞬間のやりたいことに合わせてモードを操作するわけです。
　具体的には、大きく分けて以下のモードが存在します。

| モード |説明|
|:-:|:-|
|  ノーマル |  モードの変更、カーソルの移動、テキストのヤング&ペースト・削除などを行う |
| 挿入  |  テキストを入力する |
|  ビジュアル | テキストを選択する  |
|  コマンドライン | コマンドを実行してファイル開閉、検索、置換などを行う  |

　他にも色々あったり上のモードも更に細分化されたりしますがだいたいこんな感じ。普段は基本的にノーマルモードにいて、ここを中心として必要に応じてモードを切り替えることが多いです。
　各モードに対してキーバインドが割り振られており、これのせいで初心者殺しとか色々言われたりします。初めて使う人が何事もなくテキストを編集するのはまず間違いなく無理なので、仕方ないっちゃ仕方ないですが。


## `.vimrc`について
　`.vimrc`はVimにおけるconfigファイル的なものです（"rc"は"Run Command"の略。`.bashrc`とか`.cshrc`とか、UNIX系では`.*rc`というのがよくあるネーミング）。VimにはVim scriptという組み込みのスクリプト言語があり、これで記述することでVimの挙動を設定できます。

# ぼくの`.vimrc`
　というわけで、僕の`.vimrc`を下に張っつけときます。そんなに面白いものでもないですが。

```vim
"plugin by vim-plug
call plug#begin()
    Plug 'scrooloose/nerdtree'
    Plug 'scrooloose/syntastic'
    Plug 'Shougo/neocomplete'
    Plug 'tokorom/vim-review'
    Plug 'vim-airline/vim-airline'
    Plug 'vim-airline/vim-airline-themes'
    Plug 'mattn/emmet-vim'
call plug#end()

"syntastic setup
set statusline+=%#warningmsg#
set statusline+=%{SyntasticStatuslineFlag()}
set statusline+=%*

let g:syntastic_always_populate_loc_list=1
let g:syntastic_auto_loc_list=1
let g:syntastic_check_on_open=1
let g:syntastic_check_on_wq=0

let g:vim_review#include_filetypes=['c',"python","sh","java"]
"end

"neocomplete setup
let g:neocomplete#enable_at_startup=1
let g:neocomplete#max_list=25
inoremap <expr><C-l> neocomplete#complete_common_string()
"end

"powerline setup
set t_Co=256

let g:airline_powerline_fonts = 1
let g:airline#extensions#tabline#enabled = 1
let g:airline#extensions#tabline#buffer_idx_mode = 1
let g:airline#extensions#whitespace#mixed_indent_algo = 1
let g:airline_theme = 'dark'
if !exists('g:airline_symbols')
    let g:airline_symbols = {}
endif

" unicode symbols
let g:airline_left_sep = '»'
let g:airline_left_sep = '▶'
let g:airline_right_sep = '«'
let g:airline_right_sep = '◀'
let g:airline_symbols.crypt = '🔒'
let g:airline_symbols.linenr = '☰'
let g:airline_symbols.linenr = '␊'
let g:airline_symbols.linenr = '␤'
let g:airline_symbols.linenr = '¶'
let g:airline_symbols.maxlinenr = ''
let g:airline_symbols.maxlinenr = '㏑'
let g:airline_symbols.branch = '⎇'
let g:airline_symbols.paste = 'ρ'
let g:airline_symbols.paste = 'Þ'
let g:airline_symbols.paste = '∥'
let g:airline_symbols.spell = 'Ꞩ'
let g:airline_symbols.notexists = '∄'
let g:airline_symbols.whitespace = 'Ξ'
"end

"my funcs

command! -nargs=+ Atcoder call SetAtcoder(<f-args>)

function SetAtcoder(...)
    if a:0 == 1
        if a:1 == 'd'
            so $HOME/.vim/atcoder/setup/d.vim
        elseif a:1 == 'ds'
            so $HOME/.vim/atcoder/setup/simpled.vim
        elseif a:1 == 'cpp'
            so $HOME/.vim/atcoder/setup/cpp.vim
        else
            echo "Atcoder: file type '" . a:1 . "' not found."
        endif
    elseif a:0 == 2
        if a:2 == 'old'
            if a:1 == 'd'
                so $HOME/.vim/atcoder/setup/d_2.071_0.vim
            else
                echo "Atcoder: file type '" . a:1 . " " . a:2 . "' not found."
            endif
        else
            echo "Atcoder: file type '" . a:1 . " " . a:2 . "' not found."
        endif
    else
        echo "Atcoder: too many arguments."
    endif
endfunction

command! -nargs=? LaTeXreport call SetLatexreport(<f-args>)

function SetLatexreport(...)
    if a:0 == 0
        so $HOME/.vim/latexreport/setup/default.vim
    endif

endfunction

command! LaTeXpdf call SaveAndConvertLaTeXtoPDF()

function SaveAndConvertLaTeXtoPDF()
    write
    !lpreport "%:r"
endfunction

command! ReplacePanctuations call ReplaceJapanesePancuationsTraditionalToAcademic()

function ReplaceJapanesePancuationsTraditionalToAcademic()
    %s/。/．/g
    %s/、/，/g
endfunction

"end

"basic settings

set encoding=utf-8
set number
set showmatch
set hlsearch
set synmaxcol=400
set tabstop=4
set softtabstop=4
set wildmode=list:longest
set expandtab
set shiftwidth=4
set autoindent
set cindent
set wildmenu
set history=5000
set laststatus=2
set timeoutlen=500
syntax on
filetype plugin on

let mapleader="\<Space>"

inoremap (<CR> ()<LEFT><CR><ESC><S-o>
inoremap {<CR> {}<LEFT><CR><ESC><S-o>
inoremap ( ()<LEFT>
inoremap { {}<LEFT>
inoremap [ []<LEFT>
inoremap ' ''<LEFT>
inoremap " ""<LEFT>
inoremap '<CR> '
inoremap "<CR> "
inoremap <<CR> <><LEFT>
inoremap ;<Leader><Leader> <ESC>A;
inoremap /*<CR> /**/<LEFT><LEFT>
inoremap $$ $$<LEFT>


nnoremap sh <C-h>
nnoremap sj <C-j>
nnoremap sk <C-k>
nnoremap sl <C-l>
nnoremap sw <C-w>

```

　順番に見ていきましょう。

## プラグイン関連

```vim
"plugin by vim-plug
call plug#begin()
    Plug 'scrooloose/nerdtree'
    Plug 'scrooloose/syntastic'
    Plug 'Shougo/neocomplete'
    Plug 'tokorom/vim-review'
    Plug 'vim-airline/vim-airline'
    Plug 'vim-airline/vim-airline-themes'
    Plug 'mattn/emmet-vim'
call plug#end()

"syntastic setup
set statusline+=%#warningmsg#
set statusline+=%{SyntasticStatuslineFlag()}
set statusline+=%*

let g:syntastic_always_populate_loc_list=1
let g:syntastic_auto_loc_list=1
let g:syntastic_check_on_open=1
let g:syntastic_check_on_wq=0

let g:vim_review#include_filetypes=['c',"python","sh","java"]
"end

"neocomplete setup
let g:neocomplete#enable_at_startup=1
let g:neocomplete#max_list=25
inoremap <expr><C-l> neocomplete#complete_common_string()
"end
```

　実は僕は[vim-plug](https://github.com/junegunn/vim-plug)派です。巷では[dein.vim](https://github.com/Shougo/dein.vim)が多数派なんじゃないですかね、知らんけど。dein.vimは[Shougo](https://github.com/Shougo)さんというVimプラグイン界のLv.255みたいな方が作成したプラグインマネージャで、たくさんプラグインを入れてもあんまり起動速度が落ちないらしいです。ただちょっと煩雑で、Vimガチ勢でもないしテキトーに使いたい僕は、軽く書くだけでよさそうなvim-plugを採用しています。
　ちなみにVim 8.0から標準でもプラグイン管理機能がついています。使ったことはありません。

　導入してるプラグインはこんな感じです。

| プラグイン | 説明 |
|:-:|:-|
| [nerdtree](https://github.com/preservim/nerdtree)  | Vim内でファイルブラウズができる  |
| [syntastic](https://github.com/vim-syntastic/syntastic)  | シンタックスチェッカー  |
| [neocomplete](https://github.com/Shougo/neocomplete.vim)  | 入力補完   |
| [vim-review](https://github.com/tokorom/vim-review)  | [RE:View](https://reviewml.org/ja/)という技術書執筆ツールのサポート  |
| [vim-airline](https://github.com/vim-airline/vim-airline)  |  PowerLineでVimをイケてる見た目にする（後述） |
| [emmet-vim](https://github.com/mattn/emmet-vim)  | HTMLやCSSの入力補助 ~~コンリテ課題がクソすぎて入れた~~  |

　ちなみに現在neocompleteの開発は停止され、代わって元々nvim用だった（Vim 8以降はVimにも対応）[deoplete.nvim](https://github.com/Shougo/deoplete.nvim)が開発されています。面倒だから移行してないだけです。

## vim-airlineまわり

```vim
"powerline setup
set t_Co=256

let g:airline_powerline_fonts = 1
let g:airline#extensions#tabline#enabled = 1
let g:airline#extensions#tabline#buffer_idx_mode = 1
let g:airline#extensions#whitespace#mixed_indent_algo = 1
let g:airline_theme = 'dark'
if !exists('g:airline_symbols')
    let g:airline_symbols = {}
endif

" unicode symbols
let g:airline_left_sep = '»'
let g:airline_left_sep = '▶'
let g:airline_right_sep = '«'
let g:airline_right_sep = '◀'
let g:airline_symbols.crypt = '🔒'
let g:airline_symbols.linenr = '☰'
let g:airline_symbols.linenr = '␊'
let g:airline_symbols.linenr = '␤'
let g:airline_symbols.linenr = '¶'
let g:airline_symbols.maxlinenr = ''
let g:airline_symbols.maxlinenr = '㏑'
let g:airline_symbols.branch = '⎇'
let g:airline_symbols.paste = 'ρ'
let g:airline_symbols.paste = 'Þ'
let g:airline_symbols.paste = '∥'
let g:airline_symbols.spell = 'Ꞩ'
let g:airline_symbols.notexists = '∄'
let g:airline_symbols.whitespace = 'Ξ'
"end
```
　`vim-airline`とは、[Poweline](https://github.com/powerline/powerline)（ターミナルのプロンプトをリッチにしてGitのブランチ管理とかできるツール）を用いてVimをイカした見た目にできるプラグインです。この辺の経緯は[こちら](https://qiita.com/JJ1LIS/items/0c251d8df9adfe5640c2)に詳しく書きました。
　これを使うとファイル編集のとき画面が賑やかになって楽しいです。ちょっとだけね。

## ユーザ定義コマンド
　ここまではありものを寄せ集めて便利機能を追加しただけでしたが、ここからはお手製です。


```vim
"my funcs

command! -nargs=+ Atcoder call SetAtcoder(<f-args>)

function SetAtcoder(...)
    if a:0 == 1
        if a:1 == 'd'
            so $HOME/.vim/atcoder/setup/d.vim
        elseif a:1 == 'ds'
            so $HOME/.vim/atcoder/setup/simpled.vim
        elseif a:1 == 'cpp'
            so $HOME/.vim/atcoder/setup/cpp.vim
        else
            echo "Atcoder: file type '" . a:1 . "' not found."
        endif
    elseif a:0 == 2
        if a:2 == 'old'
            if a:1 == 'd'
                so $HOME/.vim/atcoder/setup/d_2.071_0.vim
            else
                echo "Atcoder: file type '" . a:1 . " " . a:2 . "' not found."
            endif
        else
            echo "Atcoder: file type '" . a:1 . " " . a:2 . "' not found."
        endif
    else
        echo "Atcoder: too many arguments."
    endif
endfunction

```

　前半部では競プロ関係のコマンド定義をしています。あたかも競プロといえばAtCoderみたいな書き方をしていて殺されそうですが、AtCoder以外やったことないし何なら最近はAtCoderもやってないので許してください。
　僕は`~/.vim/`にシステムファイル以外も色々突っ込んでしまっています。`~/.vim/atcoder/setup/`にAtCoder用のテンプレートが色々と入っていて、実際に使う時はエディタからコマンドラインモードで`:Atcoder d`のように実行するとD言語用のテンプレートが展開されます。
　以前のAtCoderはdmd v2.071までしか対応していなくて不便でした。`import std;`が使えなかったり、UFCSが効かなくて同名のdeprecatedなpropertyが呼ばれたり......

```vim

command! -nargs=? LaTeXreport call SetLatexreport(<f-args>)

function SetLatexreport(...)
    if a:0 == 0
        so $HOME/.vim/latexreport/setup/default.vim
    endif

endfunction

command! LaTeXpdf call SaveAndConvertLaTeXtoPDF()

function SaveAndConvertLaTeXtoPDF()
    write
    !lpreport "%:r"
endfunction

command! ReplacePanctuations call ReplaceJapanesePancuationsTraditionalToAcademic()

function ReplaceJapanesePancuationsTraditionalToAcademic()
    %s/。/．/g
    %s/、/，/g
endfunction

"end
```

　後半部は $\LaTeX$ 用のコマンドです。えぇ、はい。基礎科学実験Aのために作りました。`:LaTeXreport`でテンプレートを展開して、`:LaTeXpdf`で今編集中のファイルからpdfを出力できるようになっています。あとは適当に`:!evince hoge.pdf &`とかで開けばOKです。

## 基本設定

```vim
"basic settings

set encoding=utf-8
set number
set showmatch
set hlsearch
set synmaxcol=400
set tabstop=4
set softtabstop=4
set wildmode=list:longest
set expandtab
set shiftwidth=4
set autoindent
set cindent
set wildmenu
set history=5000
set laststatus=2
set timeoutlen=500
syntax on
filetype plugin on
```

　この辺はみなさん思い思いの設定にしていると思います。`set number`で行番号表示とか。
　僕は4タブ派なので`set tabstop=4`としています。これも宗教戦争の火種なので注意ですね。あと、`set expandtab`としておくとTabキー押下時に挿入されるのがタブ文字ではなく`tabstop`分の空白文字になります。
　インデント関係はどうするのが正解なんでしょうか？普段はとりあえず`autoindent`と、C言語系文法の言語を書くことが多いので`cindent`をオンにしています。`smartindent`はよくわかんなかった（小並感）。

## キーバインド

```vim
let mapleader="\<Space>"

inoremap (<CR> ()<LEFT><CR><ESC><S-o>
inoremap {<CR> {}<LEFT><CR><ESC><S-o>
inoremap ( ()<LEFT>
inoremap { {}<LEFT>
inoremap [ []<LEFT>
inoremap ' ''<LEFT>
inoremap " ""<LEFT>
inoremap '<CR> '
inoremap "<CR> "
inoremap <<CR> <><LEFT>
inoremap ;<Leader><Leader> <ESC>A;
inoremap /*<CR> /**/<LEFT><LEFT>
inoremap $$ $$<LEFT>


nnoremap sh <C-h>
nnoremap sj <C-j>
nnoremap sk <C-k>
nnoremap sl <C-l>
nnoremap sw <C-w>
```

　これが一番悩ましい部分でしょう。例えばHTMLなら`<`と打った時点ですぐに`<>`として欲しいけど、そうすると他の言語で不便。`'`も`''`としたいけど$\LaTeX$で数式を書く時に不便。カッコの内側からでも`;<Leader>`で行末にセミコロンをつけたいけど、そうすると`foreach(i; ...)`とかの時に困る。
　あとは`Leader`をどのキーに割り振るかも難しいところです。僕はスペースキーに振っていますが、結構使いづらくて困っています。いいアイデアがあったら教えてください。

# おわりに
　（もし存在したら）電通大Vimmerで集まってvimrc読書会やりませんか？興味のある方は[Twitter](https://twitter.com/_jj1lis_uec)に連絡していただけると幸いです。